- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个应用程序,我将日志字符串保存在循环缓冲区中。当日志变满时,对于每个新插入,旧字符串将被释放以进行垃圾收集,然后它们将进入第 2 代内存。因此,最终会发生第 2 代 GC,我希望避免这种情况。
我试图将字符串编码为一个结构。令人惊讶的是,我仍然得到第 2 代 GC:s。似乎该结构仍然保留对字符串的一些引用。下面是完整的控制台应用程序。任何帮助表示赞赏。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
[StructLayout(LayoutKind.Sequential)]
public struct FixedString
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
private string str;
public FixedString(string str)
{
this.str = str;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct UTF8PackedString
{
private int length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
private byte[] str;
public UTF8PackedString(int length)
{
this.length = length;
str = new byte[length];
}
public static implicit operator UTF8PackedString(string str)
{
var obj = new UTF8PackedString(Encoding.UTF8.GetByteCount(str));
var bytes = Encoding.UTF8.GetBytes(str);
Array.Copy(bytes, obj.str, obj.length);
return obj;
}
}
const int BufferSize = 1000000;
const int LoopCount = 10000000;
static void Main(string[] args)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}",
"Type".PadRight(20), "Time", "GC(0)", "GC(1)", "GC(2)");
Console.WriteLine();
for (int i = 0; i < 5; i++)
{
TestPerformance<string>(s => s);
TestPerformance<FixedString>(s => new FixedString(s));
TestPerformance<UTF8PackedString>(s => s);
Console.WriteLine();
}
Console.ReadKey();
}
private static void TestPerformance<T>(Func<string, T> func)
{
var buffer = new T[BufferSize];
GC.Collect(2);
Stopwatch stopWatch = new Stopwatch();
var initialCollectionCounts = new int[] { GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2) };
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < LoopCount; i++)
buffer[i % BufferSize] = func(i.ToString());
stopWatch.Stop();
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}",
typeof(T).Name.PadRight(20),
stopWatch.ElapsedMilliseconds,
(GC.CollectionCount(0) - initialCollectionCounts[0]),
(GC.CollectionCount(1) - initialCollectionCounts[1]),
(GC.CollectionCount(2) - initialCollectionCounts[2])
);
}
}
}
编辑:使用 UnsafeFixedString 更新代码以完成所需的工作:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication
{
class Program
{
public unsafe struct UnsafeFixedString
{
private int length;
private fixed char str[256];
public UnsafeFixedString(int length)
{
this.length = length;
}
public static implicit operator UnsafeFixedString(string str)
{
var obj = new UnsafeFixedString(str.Length);
for (int i = 0; i < str.Length; i++)
obj.str[i] = str[i];
return obj;
}
}
const int BufferSize = 1000000;
const int LoopCount = 10000000;
static void Main(string[] args)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}",
"Type".PadRight(20), "Time", "GC(0)", "GC(1)", "GC(2)");
Console.WriteLine();
for (int i = 0; i < 5; i++)
{
TestPerformance(s => s);
TestPerformance<UnsafeFixedString>(s => s);
Console.WriteLine();
}
Console.ReadKey();
}
private static void TestPerformance<T>(Func<string, T> func)
{
var buffer = new T[BufferSize];
GC.Collect(2);
Stopwatch stopWatch = new Stopwatch();
var initialCollectionCounts = new int[] { GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2) };
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < LoopCount; i++)
buffer[i % BufferSize] = func(String.Format("{0}", i));
stopWatch.Stop();
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}",
typeof(T).Name.PadRight(20),
stopWatch.ElapsedMilliseconds,
(GC.CollectionCount(0) - initialCollectionCounts[0]),
(GC.CollectionCount(1) - initialCollectionCounts[1]),
(GC.CollectionCount(2) - initialCollectionCounts[2])
);
}
}
}
我电脑上的输出是:
Type Time GC(0) GC(1) GC(2)
String 5746 160 71 19
UnsafeFixedString 5345 418 0 0
最佳答案
struct
不足为奇用string
字段在这里有所作为:a string
字段总是只是对托管堆上对象的引用——具体来说,一个string
某处的对象。 string
仍将存在并最终仍会导致 GC2。
“解决”这个问题的唯一方法是完全不将其作为对象;唯一的方法(不完全超出托管内存)是使用 fixed
缓冲区:
public unsafe struct FixedString
{
private fixed char str[100];
}
在这里,每个 结构实例 FixedString
为数据保留了 200 个字节。 str
只是 char*
的相对偏移量这标志着这个保留的开始。然而,处理这个很棘手 - 并且需要 unsafe
整个代码。另请注意,每个 FixedString
无论您实际上是想存储 3 个字符还是 170 个字符,都会保留相同数量的空间。为避免内存问题,您需要使用空终止符或单独存储有效负载长度。
请注意,在 .NET 4.5 中, <gcAllowVeryLargeObjects>
支持使得拥有此类值的适当大小的数组(例如 FixedString[]
)成为可能 - 但请注意,您不想经常复制数据。为避免这种情况,您需要始终在数组中留出空闲空间(这样您就不会复制整个数组只是为了添加一项),并通过 ref
处理单个项。 ,即
FixedString[] data = ...
int index = ...
ProcessItem(ref data[index]);
void ProcessItem(ref FixedString item) {
// ...
}
在这里item
直接与数组中的元素对话——我们在任何时候都没有复制数据。
现在我们只有一个对象 - 数组本身。
关于c# - 如何避免长生命周期字符串导致第 2 代垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18957421/
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我正在尝试将 JSON 发送到我的服务器并作为结果检索 JSON。例如发送用户名和密码并取回 token 和其他内容。 这就是我正在为发送的 HTTP 请求所做的。我现在如何检索同一请求中的内容?
我有以下 xts 矩阵: > options(digits.secs = 6) > set.seed(1234) > xts(1:10, as.POSIXlt(1366039619, tz="EST"
我目前正在开发一个应用程序,当用户到达某个位置时,它会提醒用户。我希望这个应用程序也在后台运行并搜索解决方案。 在 AppStore 中,我发现了一款名为“Sleep Cycle”的应用程序,它可
我想创建一个基于 farbtastic color picker 的颜色选择器。我想要实现的是添加我想要链接到色轮的 RGB slider 。这是我到目前为止所拥有的。 app.controller(
RFC 5545 允许 RDATE 属性具有 PERIOD 数据类型。该数据类型的语义是什么?据我所知,这是未指定的。它会改变事件的持续时间吗?如果时区更改且没有持续时间怎么办? 最佳答案 尽管我
在 CodinGame学习平台,C# 教程中用作示例的问题之一是: The aim of this exercise is to check the presence of a number in a
我听说网上有一本英特尔书,它描述了特定汇编指令所需的 CPU 周期,但我找不到(经过努力)。谁能告诉我如何找到CPU周期? 这是一个例子,在下面的代码中,mov/lock 是 1 个 CPU 周期,x
据我所知,Java GC有次要GC(低成本)和主要GC周期(高成本)。如果对象在本地范围内,则会在 Minor GC 中清理它。如果对象的引用存储在代码中的其他位置,则它会在主 GC 中被清除。 例如
到目前为止,我有一个很好的自旋锁,可以用作 intendend: std::atomic_flag barrier = ATOMIC_FLAG_INIT; inline void lo
晚上好,我将 cycle2 与 prev 和 next 函数一起使用,但我无法将 prev 和 next 函数置于图像下方的中心。我环顾四周,我知道这会很愚蠢,但我就是看不到它。非常令人沮丧。谢谢加里
出于教育目的,我想知道在优化(在不同级别)和编译之后执行函数需要多少 CPU 周期。有没有办法分析代码或可执行文件以获得可重现的答案?我在 64 位 Windows 7 Pro 上使用 Eclipse
我想彻底测量和调整我的 C/C++ 代码,以便在 x86_64 系统上更好地使用缓存。我知道如何使用计数器(我的 Windows 机器上的 QueryPerformanceCounter)来测量时间,
我尝试将一些数据分组到每四周一次的存储桶中,并使用 pd.Grouper(key='created_at', freq='4W')。我希望这些组是这样的,如果我有从 2019-08-26 到 2019
我正在做一个关于随机数的大型学校项目,但我找不到 Math.random() 的句点。我安装了 7.0.800.15 版本,并且正在使用 Windows 10 计算机。我试过用一个简单的程序来确定周期
我正在努力解决我们生产环境中垃圾收集利用率高的问题,我想知道设置一个大的堆大小来保证老年代永远不会被填满是否会阻止触发主要的 GC 周期。 为了实现这一点,我想有一个特定的阈值标记会触发主要的 GC
我想测量在 Python 3 中执行加法运算所需的时钟周期数。 我写了一个程序来计算加法运算的平均值: from timeit import timeit def test(n): for i
我正在寻找一种方法来测量线程上的函数调用所花费的 cpu 周期。 示例伪代码: void HostFunction() { var startTick = CurrentThread.Cur
就 CPU 周期而言,malloc() 的成本是多少?(Vista/OS,最新版本的 gcc,最高优化级别,...) 基本上,我正在实现一个复杂的 DAG 结构(类似于链表)由一些 16B(不太常见)
C/C++ 中的类型转换会导致额外的 CPU 周期吗? 我的理解是,至少在某些情况下应该消耗额外的 CPU 周期。就像从浮点类型转换为整数一样,CPU 需要将浮点结构转换为整数。 float a=2.
我是一名优秀的程序员,十分优秀!