Skip to content

Commit

Permalink
Merge branch 'v10'
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Sep 2, 2024
2 parents 1c1cdca + 6402196 commit 1c95bd6
Show file tree
Hide file tree
Showing 16 changed files with 983 additions and 512 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/publish-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: publish-beta

on:
push:
branches: [ master, dev ]
branches: [ master, dev, v10 ]
paths:
- 'NewLife.Core/**'
pull_request:
branches: [ master, dev ]
branches: [ master, dev, v10 ]
paths:
- 'NewLife.Core/**'
workflow_dispatch:
Expand Down
90 changes: 90 additions & 0 deletions NewLife.Core/Common/Runtime.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Collections;
using System.Diagnostics;
using System.Runtime;
using System.Runtime.InteropServices;
using NewLife.Log;

namespace NewLife;

Expand Down Expand Up @@ -112,6 +114,15 @@ public static Int64 TickCount64
}
#endif

private static Int32 _ProcessId;
#if NET5_0_OR_GREATER
/// <summary>当前进程Id</summary>
public static Int32 ProcessId => _ProcessId > 0 ? _ProcessId : _ProcessId = Environment.ProcessId;
#else
/// <summary>当前进程Id</summary>
public static Int32 ProcessId => _ProcessId > 0 ? _ProcessId : _ProcessId = Process.GetCurrentProcess().Id;
#endif

/// <summary>
/// 获取环境变量。不区分大小写
/// </summary>
Expand Down Expand Up @@ -171,4 +182,83 @@ public static Boolean CreateConfigOnMissing
set { _createConfigOnMissing = value; }
}
#endregion

#region 内存
/// <summary>释放内存。GC回收后再释放虚拟内存</summary>
/// <param name="processId">进程Id。默认0表示当前进程</param>
/// <param name="gc">是否GC回收</param>
/// <param name="workingSet">是否释放工作集</param>
public static Boolean FreeMemory(Int32 processId = 0, Boolean gc = true, Boolean workingSet = true)
{
if (processId <= 0) processId = ProcessId;

var p = Process.GetProcessById(processId);
if (p == null) return false;

if (processId != ProcessId) gc = false;

var log = XTrace.Log;
if (log != null && log.Enable && log.Level <= LogLevel.Debug)
{
p ??= Process.GetCurrentProcess();
var gcm = GC.GetTotalMemory(false) / 1024;
var ws = p.WorkingSet64 / 1024;
var prv = p.PrivateMemorySize64 / 1024;
if (gc)
log.Debug("[{3}/{4}]开始释放内存:GC={0:n0}K,WorkingSet={1:n0}K,PrivateMemory={2:n0}K", gcm, ws, prv, p.ProcessName, p.Id);
else
log.Debug("[{3}/{4}]开始释放内存:WorkingSet={1:n0}K,PrivateMemory={2:n0}K", gcm, ws, prv, p.ProcessName, p.Id);
}

if (gc)
{
var max = GC.MaxGeneration;
var mode = GCCollectionMode.Forced;
#if NET8_0_OR_GREATER
mode = GCCollectionMode.Aggressive;
#endif
#if NET451_OR_GREATER || NETSTANDARD || NETCOREAPP
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
#endif
GC.Collect(max, mode);
GC.WaitForPendingFinalizers();
GC.Collect(max, mode);
}

if (workingSet)
{
if (Runtime.Windows)
{
try
{
p ??= Process.GetProcessById(processId);
EmptyWorkingSet(p.Handle);
}
catch (Exception ex)
{
log?.Error("EmptyWorkingSet失败:{0}", ex.Message);
return false;
}
}
}

if (log != null && log.Enable && log.Level <= LogLevel.Debug)
{
p ??= Process.GetProcessById(processId);
p.Refresh();
var gcm = GC.GetTotalMemory(false) / 1024;
var ws = p.WorkingSet64 / 1024;
var prv = p.PrivateMemorySize64 / 1024;
if (gc)
log.Debug("[{3}/{4}]释放内存完成:GC={0:n0}K,WorkingSet={1:n0}K,PrivateMemory={2:n0}K", gcm, ws, prv, p.ProcessName, p.Id);
else
log.Debug("[{3}/{4}]释放内存完成:WorkingSet={1:n0}K,PrivateMemory={2:n0}K", gcm, ws, prv, p.ProcessName, p.Id);
}

return true;
}

[DllImport("psapi.dll", SetLastError = true)]
internal static extern Boolean EmptyWorkingSet(IntPtr hProcess);
#endregion
}
6 changes: 3 additions & 3 deletions NewLife.Core/Common/Utility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ public static class Utility
/// <returns></returns>
public static DateTimeOffset ToDateTimeOffset(this Object? value, DateTimeOffset defaultValue) => Convert.ToDateTimeOffset(value, defaultValue);

/// <summary>去掉时间日期秒后面部分,可指定毫秒ms、分m、小时h</summary>
/// <summary>去掉时间日期秒后面部分,可指定毫秒ms、秒s、分m、小时h</summary>
/// <param name="value">时间日期</param>
/// <param name="format">格式字符串,默认s格式化到秒,ms格式化到毫秒</param>
/// <returns></returns>
public static DateTime Trim(this DateTime value, String format = "s") => Convert.Trim(value, format);

/// <summary>去掉时间日期秒后面部分,可指定毫秒</summary>
/// <summary>去掉时间日期秒后面部分,可指定毫秒ms、秒s、分m、小时h</summary>
/// <param name="value">时间日期</param>
/// <param name="format">格式字符串,默认s格式化到秒,ms格式化到毫秒</param>
/// <returns></returns>
Expand Down Expand Up @@ -616,7 +616,7 @@ private static String ToDBC(String str)
return new String(ch);
}

/// <summary>去掉时间日期秒后面部分,可指定毫秒ms、分m、小时h</summary>
/// <summary>去掉时间日期秒后面部分,可指定毫秒ms、秒s、分m、小时h</summary>
/// <param name="value">时间日期</param>
/// <param name="format">格式字符串,默认s格式化到秒,ms格式化到毫秒</param>
/// <returns></returns>
Expand Down
12 changes: 2 additions & 10 deletions NewLife.Core/Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public static TConfig Current
{
// OnLoad 中可能有变化,存回去
//prv.Save(config);
config.Save();
if (!prv.IsNew || Runtime.CreateConfigOnMissing) config.Save();
}
catch (Exception ex)
{
Expand All @@ -114,14 +114,6 @@ protected virtual void OnLoaded() { }

/// <summary>保存到配置文件中去</summary>
//[Obsolete("=>Provider.Save")]
public virtual void Save()
{
var prv = Provider;
if (prv == null) return;

// 是否创建默认配置
if (!prv.IsNew || Runtime.CreateConfigOnMissing)
prv.Save(this);
}
public virtual void Save() => Provider?.Save(this);
#endregion
}
65 changes: 16 additions & 49 deletions NewLife.Core/Extension/ProcessHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,40 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Linq;
using NewLife.Configuration;
using NewLife.Log;

namespace NewLife;

/// <summary>进程助手类</summary>
/// <remarks>
/// 文档 https://newlifex.com/core/string_helper
/// 文档 https://newlifex.com/core/process_helper
/// </remarks>
public static class ProcessHelper
{
#region 进程查找
/// <summary>获取进程名。dotnet/java进程取文件名,Windows系统中比较耗时</summary>
/// <summary>获取二级进程名。默认一级,如果是dotnet/java则取二级</summary>
/// <param name="process"></param>
/// <returns></returns>
public static String GetProcessName(this Process process)
{
var name = process.ProcessName;

//if (Runtime.Linux)
//{
// try
// {
// var file = $"/proc/{process.Id}/cmdline";
// if (File.Exists(file))
// {
// var lines = File.ReadAllText(file).Trim('\0', ' ').Split('\0');
// if (lines.Length > 1) name = Path.GetFileNameWithoutExtension(lines[1]);
// }
// }
// catch { }
//}
//else if (Runtime.Windows)
//{
// try
// {
// var dic = MachineInfo.ReadWmic("process where processId=" + process.Id, "commandline");
// if (dic.TryGetValue("commandline", out var str) && !str.IsNullOrEmpty())
// {
// var ss = str.Split(' ').Select(e => e.Trim('\"')).ToArray();
// str = ss.FirstOrDefault(e => e.EndsWithIgnoreCase(".dll", ".jar"));
// if (!str.IsNullOrEmpty()) name = Path.GetFileNameWithoutExtension(str);
// }
// }
// catch { }
//}

var args = GetCommandLineArgs(process.Id);
if (args != null)
var pname = process.ProcessName;
if (pname == "dotnet" || "*/dotnet".IsMatch(pname))
{

var args = GetCommandLineArgs(process.Id);
if (args != null && args.Length >= 2 && args[0].Contains("dotnet"))
{
return Path.GetFileNameWithoutExtension(args[1]);
}
}

return name;
}

/// <summary>获取二级进程名。默认一级,如果是dotnet/java则取二级</summary>
/// <param name="process"></param>
/// <returns></returns>
public static String GetProcessName2(this Process process)
{
var pname = process.ProcessName;
if (
pname == "dotnet" || "*/dotnet".IsMatch(pname) ||
pname == "java" || "*/java".IsMatch(pname))
if (pname == "java" || "*/java".IsMatch(pname))
{
return GetProcessName(process);
var args = GetCommandLineArgs(process.Id);
if (args != null && args.Length >= 3 && args[0].Contains("java") && args[1] == "-jar")
{
return Path.GetFileNameWithoutExtension(args[2]);
}
}

return pname;
Expand Down
64 changes: 32 additions & 32 deletions NewLife.Core/Extension/StringHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,46 +162,46 @@ public static Int32[] SplitAsInt(this String? value, params String[] separators)
return dic;
}

/// <summary>
/// 在.netCore需要区分该部分内容
/// </summary>
/// <param name="value"></param>
/// <param name="nameValueSeparator"></param>
/// <param name="separator"></param>
/// <param name="trimQuotation"></param>
/// <returns></returns>
public static IDictionary<String, String> SplitAsDictionaryT(this String? value, Char nameValueSeparator = '=', Char separator = ';', Boolean trimQuotation = false)
{
var dic = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
if (value == null || value.IsNullOrWhiteSpace()) return dic;
///// <summary>
///// 在.netCore需要区分该部分内容
///// </summary>
///// <param name="value"></param>
///// <param name="nameValueSeparator"></param>
///// <param name="separator"></param>
///// <param name="trimQuotation"></param>
///// <returns></returns>
//public static IDictionary<String, String> SplitAsDictionaryT(this String? value, Char nameValueSeparator = '=', Char separator = ';', Boolean trimQuotation = false)
//{
// var dic = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
// if (value == null || value.IsNullOrWhiteSpace()) return dic;

//if (nameValueSeparator == null) nameValueSeparator = '=';
//if (separator == null || separator.Length <= 0) separator = new String[] { ",", ";" };
// //if (nameValueSeparator == null) nameValueSeparator = '=';
// //if (separator == null || separator.Length <= 0) separator = new String[] { ",", ";" };

var ss = value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
if (ss == null || ss.Length <= 0) return dic;
// var ss = value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
// if (ss == null || ss.Length <= 0) return dic;

foreach (var item in ss)
{
var p = item.IndexOf(nameValueSeparator);
if (p <= 0) continue;
// foreach (var item in ss)
// {
// var p = item.IndexOf(nameValueSeparator);
// if (p <= 0) continue;

var key = item[..p].Trim();
var val = item[(p + 1)..].Trim();
// var key = item[..p].Trim();
// var val = item[(p + 1)..].Trim();


// 处理单引号双引号
if (trimQuotation && !val.IsNullOrEmpty())
{
if (val[0] == '\'' && val[^1] == '\'') val = val.Trim('\'');
if (val[0] == '"' && val[^1] == '"') val = val.Trim('"');
}
// // 处理单引号双引号
// if (trimQuotation && !val.IsNullOrEmpty())
// {
// if (val[0] == '\'' && val[^1] == '\'') val = val.Trim('\'');
// if (val[0] == '"' && val[^1] == '"') val = val.Trim('"');
// }

dic[key] = val;
}
// dic[key] = val;
// }

return dic;
}
// return dic;
//}

/// <summary>把一个列表组合成为一个字符串,默认逗号分隔</summary>
/// <param name="value"></param>
Expand Down
31 changes: 23 additions & 8 deletions NewLife.Core/Http/TinyHttpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,29 @@ protected virtual async Task<Packet> ReadChunkAsync(Packet body)
var total = chunk.Total;
while (total < len)
{
pk = await SendDataAsync(null, null).ConfigureAwait(false);

// 结尾的间断符号(如换行或00)。这里有可能一个数据包里面同时返回多个分片,暂时不支持
if (total + pk.Total > len) pk = pk.Slice(0, len - total);

last.Append(pk);
last = pk;
total += pk.Total;
var pk2 = await SendDataAsync(null, null).ConfigureAwait(false);
if (pk != null)
pk.Append(pk2);
else
pk = pk2;

// 结尾的间断符号(如换行或00)。这里有可能一个数据包里面同时返回多个分片
var count = len - total;
if (pk != null && count <= pk.Total)
{
var pk3 = pk.Slice(0, count);

last.Append(pk3);
last = pk3;
total += pk3.Total;

// 如果还有剩余,作为下一个chunk
count += 2;
if (count < pk.Total)
pk = pk.Slice(count);
else
pk = null;
}
}

// 还有粘包数据,继续分析
Expand Down
Loading

0 comments on commit 1c95bd6

Please sign in to comment.