Skip to content
6 changes: 6 additions & 0 deletions PCL.Core/App/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,11 @@ partial class HideConfigGroup
/// </summary>
[ConfigItem<int>("LaunchRamCustom", 15, ConfigSource.Local)] public partial int CustomMemorySize { get; set; }

/// <summary>
/// 自定义初始堆大小(-Xms)的滑块刻度值,0 表示不主动设置。仅在手动分配模式下生效,且实际值不会超过最大堆。
/// </summary>
[ConfigItem<int>("LaunchRamCustomInitial", 0, ConfigSource.Local)] public partial int CustomInitialMemorySize { get; set; }

/// <summary>
/// 是否固定堆大小:启用后额外追加 -Xms 并使其等于 -Xmx,隐式禁用内存归还以降低延迟抖动、利于 ZGC。见 #3282。
/// </summary>
Expand Down Expand Up @@ -619,6 +624,7 @@ partial class HideConfigGroup
[ConfigItem<bool>("VersionUseDebugLog4j2Config", false)] public partial ArgConfig<bool> UseDebugLof4j2Config { get; }
[ConfigItem<int>("VersionRamType", 2)] public partial ArgConfig<int> MemorySolution { get; }
[ConfigItem<int>("VersionRamCustom", 15)] public partial ArgConfig<int> CustomMemorySize { get; }
[ConfigItem<int>("VersionRamCustomInitial", 0)] public partial ArgConfig<int> CustomInitialMemorySize { get; }
[ConfigItem<string>("VersionArgumentTitle", "")] public partial ArgConfig<string> Title { get; }
[ConfigItem<bool>("VersionArgumentTitleEmpty", false)] public partial ArgConfig<bool> UseGlobalTitle { get; }
[ConfigItem<string>("VersionArgumentInfo", "")] public partial ArgConfig<string> TypeInfo { get; }
Expand Down
5 changes: 5 additions & 0 deletions PCL.Core/App/Localization/Languages/en-GB.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,11 @@
<sys:String x:Key="Setup.Launch.Memory.Auto.ToolTip">Dynamically adjust the memory allocated to the game based on the installed mods and available system memory.</sys:String>
<sys:String x:Key="Setup.Launch.Memory.AvailableSuffix">Available: {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.GameAllocation">Game allocation</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max">Maximum memory (-Xmx)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max.ToolTip">The maximum heap memory the game can use</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial">Initial memory (-Xms)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial.ToolTip">The heap memory pre-allocated when the game starts, which can be lower than the maximum heap (-Xmx). Set to 0 to let the JVM decide. Only takes effect when memory allocation is set to Custom, and has no effect when Lock memory allocation is enabled.</sys:String>
<sys:String x:Key="Setup.Launch.Memory.InitialSuffix">initial {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Title">Game memory</sys:String>
<sys:String x:Key="Setup.Launch.Memory.UsedTotal">Used / installed memory</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Warning.Java32Bit">32-bit Java can only allocate up to 1 GiB of memory. It is strongly recommended to use 64-bit Java!</sys:String>
Expand Down
5 changes: 5 additions & 0 deletions PCL.Core/App/Localization/Languages/en-US.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,11 @@
<sys:String x:Key="Setup.Launch.Memory.Auto.ToolTip">Dynamically adjust the memory allocated to the game based on the installed mods and available system memory.</sys:String>
<sys:String x:Key="Setup.Launch.Memory.AvailableSuffix">Available: {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.GameAllocation">Game allocation</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max">Maximum memory (-Xmx)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max.ToolTip">The maximum heap memory the game can use</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial">Initial memory (-Xms)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial.ToolTip">The heap memory pre-allocated when the game starts, which can be lower than the maximum heap (-Xmx). Set to 0 to let the JVM decide. Only takes effect when memory allocation is set to Custom, and has no effect when Lock memory allocation is enabled.</sys:String>
<sys:String x:Key="Setup.Launch.Memory.InitialSuffix">initial {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Title">Game memory</sys:String>
<sys:String x:Key="Setup.Launch.Memory.UsedTotal">Used / installed memory</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Warning.Java32Bit">32-bit Java can only allocate up to 1 GiB of memory. It is strongly recommended to use 64-bit Java!</sys:String>
Expand Down
5 changes: 5 additions & 0 deletions PCL.Core/App/Localization/Languages/zh-CN.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,11 @@
<sys:String x:Key="Setup.Launch.Memory.Auto.ToolTip">根据安装的模组量与电脑剩余内存,动态调整为游戏分配的内存</sys:String>
<sys:String x:Key="Setup.Launch.Memory.AvailableSuffix">可用 {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.GameAllocation">游戏分配</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max">最大内存(-Xmx)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max.ToolTip">游戏可使用的最大堆内存大小</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial">初始内存(-Xms)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial.ToolTip">游戏启动时预先分配的堆内存大小,可以低于最大堆(-Xmx)。设为 0 表示不主动设置,由 JVM 自行决定。仅在手动配置内存分配时生效,启用「锁定内存分配」时不生效。</sys:String>
<sys:String x:Key="Setup.Launch.Memory.InitialSuffix">初始 {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Title">游戏内存</sys:String>
<sys:String x:Key="Setup.Launch.Memory.UsedTotal">已使用内存 / 已安装内存</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Warning.Java32Bit">32 位 Java 只能分配最多 1 GiB 的内存。强烈建议换用 64 位的 Java!</sys:String>
Expand Down
5 changes: 5 additions & 0 deletions PCL.Core/App/Localization/Languages/zh-TW.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,11 @@
<sys:String x:Key="Setup.Launch.Memory.Auto.ToolTip">根據安裝的模組量與電腦剩餘記憶體,動態調整為遊戲分配的記憶體</sys:String>
<sys:String x:Key="Setup.Launch.Memory.AvailableSuffix">可用 {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.GameAllocation">遊戲分配</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max">最大記憶體(-Xmx)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Max.ToolTip">遊戲可使用的最大堆積記憶體大小</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial">初始記憶體(-Xms)</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Initial.ToolTip">遊戲啟動時預先分配的堆積記憶體大小,可以低於最大堆(-Xmx)。設為 0 表示不主動設定,由 JVM 自行決定。僅在手動配置記憶體分配時生效,啟用「鎖定記憶體分配」時不生效。</sys:String>
<sys:String x:Key="Setup.Launch.Memory.InitialSuffix">初始 {0} GiB</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Title">遊戲記憶體</sys:String>
<sys:String x:Key="Setup.Launch.Memory.UsedTotal">已使用記憶體 / 已安裝記憶體</sys:String>
<sys:String x:Key="Setup.Launch.Memory.Warning.Java32Bit">32 位元 Java 只能分配最多 1 GiB 的記憶體。強烈建議換用 64 位元的 Java!</sys:String>
Expand Down
37 changes: 31 additions & 6 deletions Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2135,10 +2135,22 @@ internal static void SecretLaunchJvmArgs(ref List<string> dataList)
var maxHeapArg = Math.Floor(totalRamMb).ToString(CultureInfo.InvariantCulture);
dataList.Add("-Xmn" + Math.Floor(totalRamMb * 0.15).ToString(CultureInfo.InvariantCulture) + "m");
dataList.Add("-Xmx" + maxHeapArg + "m");
// #3282: 固定堆大小时追加 -Xms 使其等于 -Xmx(复用同一数值以保持一致),隐式禁用内存归还降低延迟抖动、利于 ZGC。
// 若 dataList 中已存在 -Xms(例如用户自定义参数已设)则跳过,避免重复/冲突。
if (Config.Launch.LockMemory && !dataList.Any(d => d.Contains("-Xms", StringComparison.OrdinalIgnoreCase)))
dataList.Add("-Xms" + maxHeapArg + "m");
if (!dataList.Any(d => d.Contains("-Xms", StringComparison.OrdinalIgnoreCase)))
Comment thread
whitecat346 marked this conversation as resolved.
{
if (Config.Launch.LockMemory)
{
// #3282: 固定堆大小时追加 -Xms 使其等于 -Xmx(复用同一数值以保持一致),隐式禁用内存归还降低延迟抖动、利于 ZGC。
dataList.Add("-Xms" + maxHeapArg + "m");
}
else
{
// #3511: 支持自定义初始堆大小(-Xms),可低于最大堆。
var initialRam = PageInstanceSetup.GetInitialRam(ModInstanceList.McMcInstanceSelected);
if (initialRam.HasValue)
dataList.Add("-Xms" + Math.Floor(initialRam.Value * 1024d).ToString(CultureInfo.InvariantCulture) + "m");
}
}
if (!dataList.Any(d => d.Contains("-Dlog4j2.formatMsgNoLookups=true")))
dataList.Add("-Dlog4j2.formatMsgNoLookups=true");
}
Expand Down Expand Up @@ -2467,10 +2479,23 @@ private static string McLaunchArgumentsJvmOld(McInstance instance)
var maxHeapArg = Math.Floor(PageInstanceSetup.GetRam(ModInstanceList.McMcInstanceSelected,
!mcLaunchJavaSelected.Installation.Is64Bit) * 1024d);
dataList.Add("-Xmx" + maxHeapArg + "m");
// #3282: 固定堆大小时追加 -Xms 使其等于 -Xmx(复用同一数值以保持一致),隐式禁用内存归还降低延迟抖动、利于 ZGC。
// 若 dataList 中已存在 -Xms(例如用户自定义参数已设)则跳过,避免重复/冲突。
if (Config.Launch.LockMemory && !dataList.Any(d => d.Contains("-Xms", StringComparison.OrdinalIgnoreCase)))
dataList.Add("-Xms" + maxHeapArg + "m");
if (!dataList.Any(d => d.Contains("-Xms", StringComparison.OrdinalIgnoreCase)))
{
if (Config.Launch.LockMemory)
{
// #3282: 固定堆大小时追加 -Xms 使其等于 -Xmx(复用同一数值以保持一致),隐式禁用内存归还降低延迟抖动、利于 ZGC。
dataList.Add("-Xms" + maxHeapArg + "m");
}
else
{
// #3511: 支持自定义初始堆大小(-Xms),可低于最大堆。
var initialRam = PageInstanceSetup.GetInitialRam(ModInstanceList.McMcInstanceSelected,
!mcLaunchJavaSelected.Installation.Is64Bit);
if (initialRam.HasValue)
dataList.Add("-Xms" + Math.Floor(initialRam.Value * 1024d).ToString(CultureInfo.InvariantCulture) + "m");
}
}
dataList.Add("\"-Djava.library.path=" + GetNativesFolder() + "\"");
dataList.Add("-cp ${classpath}"); // 把支持库添加进启动参数表

Expand Down
35 changes: 30 additions & 5 deletions Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="9" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

Expand All @@ -124,19 +125,26 @@
Width="110"
x:Name="RadioRamType0"
Tag="VersionRamType/0"
Margin="0,0,20,0"
Margin="0,0,20,9"
ToolTip="{DynamicResource Setup.Launch.Memory.Auto.ToolTip}"
ToolTipService.Placement="Right"
ToolTipService.HorizontalOffset="-10"
ToolTipService.VerticalOffset="-3" />

<local:MyRadioBox
Grid.Row="3" Grid.Column="0"
Grid.Row="2" Grid.Column="0"
Text="{DynamicResource Common.Option.Customize}"
Width="110"
x:Name="RadioRamType1"
Tag="VersionRamType/1"
Margin="0,0,20,0" />
Margin="0,0,20,9" />

<TextBlock
Grid.Row="3" Grid.Column="0"
Text="{DynamicResource Setup.Launch.Memory.Max}"
VerticalAlignment="Center"
Margin="0,0,20,9"
ToolTip="{DynamicResource Setup.Launch.Memory.Max.ToolTip}" />

<local:MySlider
Grid.Row="3" Grid.Column="1"
Expand All @@ -145,7 +153,24 @@
Tag="VersionRamCustom"
MaxValue="49"
Value="13"
Margin="0,0,12,0" />
Margin="0,0,12,9" />

<TextBlock
Grid.Row="4" Grid.Column="0"
Text="{DynamicResource Setup.Launch.Memory.Initial}"
VerticalAlignment="Center"
Margin="0,0,20,0"
ToolTip="{DynamicResource Setup.Launch.Memory.Initial.ToolTip}" />

<local:MySlider
Grid.Row="4" Grid.Column="1"
IsEnabled="False"
x:Name="SliderRamInitialCustom"
Tag="VersionRamCustomInitial"
MaxValue="49"
Value="0"
Margin="0,0,12,0"
ToolTip="{DynamicResource Setup.Launch.Memory.Initial.ToolTip}" />
</Grid>
<Grid x:Name="PanRamDisplay" Margin="0,11,2,0" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public PageInstanceSetup()
RadioRamType0.Check += RadioBoxChange;
RadioRamType1.Check += RadioBoxChange;
SliderRamCustom.Change += SliderChange;
SliderRamInitialCustom.Change += SliderChange;

ComboServerLoginRequire.SelectionChanged += ComboServerLogin_Changed;
TextServerAuthServer.TextChanged += TextBoxChange;
Expand Down Expand Up @@ -107,6 +108,7 @@ public void Reload()
var ramType = Config.Instance.MemorySolution[PageInstanceLeft.McInstance.PathInstance];
((MyRadioBox)FindName("RadioRamType" + ramType)).Checked = true;
SliderRamCustom.Value = Config.Instance.CustomMemorySize[PageInstanceLeft.McInstance.PathInstance];
SliderRamInitialCustom.Value = Config.Instance.CustomInitialMemorySize[PageInstanceLeft.McInstance.PathInstance];
RamType(ramType);

// 服务器
Expand Down Expand Up @@ -248,6 +250,8 @@ public void RamType(int type)
if (SliderRamCustom is null)
return;
SliderRamCustom.IsEnabled = type == 1;
// 锁定内存为全局配置,启用时 -Xms 恒等于 -Xmx,初始内存设置不生效
SliderRamInitialCustom.IsEnabled = type == 1 && !Config.Launch.LockMemory;
}

/// <summary>
Expand Down Expand Up @@ -277,7 +281,12 @@ public void RefreshRam(bool showAnim)
else
SliderRamCustom.MaxValue = (int)Math.Round(Math.Floor((ramTotal - 16d) / 2d) + 33d);
// 设置文本
LabRamGame.Text = $"{Lang.Number(ramGame, "N1")} GiB{(ramGame != ramGameActual ? $" ({Lang.Text("Setup.Launch.Memory.AvailableSuffix", Lang.Number(ramGameActual, "N1"))})" : "")}";
var ramInitial = GetInitialRam(PageInstanceLeft.McInstance);
var initialText = ramInitial.HasValue ? Lang.Text("Setup.Launch.Memory.InitialSuffix", Lang.Number(ramInitial.Value, "N1")) : "";
var availableText = ramGame != ramGameActual ? Lang.Text("Setup.Launch.Memory.AvailableSuffix", Lang.Number(ramGameActual, "N1")) : "";
var suffixText = !string.IsNullOrEmpty(initialText) && !string.IsNullOrEmpty(availableText) ? initialText + ", " : initialText;
suffixText += availableText;
LabRamGame.Text = $"{Lang.Number(ramGame, "N1")} GiB{(suffixText.Length > 0 ? $" ({suffixText})" : "")}";
LabRamUsed.Text = $"{Lang.Number(ramUsed, "N1")} GiB";
LabRamTotal.Text = $" / {Lang.Number(ramTotal, "N1")} GiB";
LabRamWarn.Visibility =
Expand Down Expand Up @@ -524,14 +533,7 @@ public static double GetRam(McInstance version, bool? is32BitJava = default)
{
// 手动配置
var value = Config.Instance.CustomMemorySize[instancePath];
if (value <= 12)
ramGive = value * 0.1d + 0.3d;
else if (value <= 25)
ramGive = (value - 12) * 0.5d + 1.5d;
else if (value <= 33)
ramGive = (value - 25) * 1 + 8;
else
ramGive = (value - 33) * 2 + 16;
ramGive = PageSetupLaunch.GetRamFromTick(value);
}

// 若使用 32 位 Java,则限制为 1G
Expand All @@ -540,6 +542,29 @@ public static double GetRam(McInstance version, bool? is32BitJava = default)
return ramGive;
}

/// <summary>
/// 获取当前设置的初始堆大小(-Xms)。单位为 GB;未启用自定义初始大小时返回 null。
/// </summary>
public static double? GetInitialRam(McInstance version, bool? is32BitJava = default)
{
// 锁定内存为全局配置,启用时 -Xms 恒等于 -Xmx,由锁定内存逻辑处理
if (Config.Launch.LockMemory)
return null;
var instancePath = version?.PathInstance;
switch (Config.Instance.MemorySolution[instancePath])
{
case 2:
return PageSetupLaunch.GetInitialRam(version, true, is32BitJava);
case 1:
var initialTick = Config.Instance.CustomInitialMemorySize[instancePath];
if (initialTick <= 0)
return null;
return Math.Min(PageSetupLaunch.GetRamFromTick(initialTick), GetRam(version, is32BitJava));
default:
return null;
}
}

#endregion

#region 服务器
Expand Down
Loading
Loading