为何类中的TArray<string>无法自动释放?
Delphi中TArray内存释放与二次运行内存差异的解析
关于TArray未随类实例释放的问题
- 引用计数的独立逻辑:
TArray<string>是动态数组,和string确实都是引用计数类型,但它们的引用计数和类实例的生命周期是分离的。类实例被释放时,只是把类里的数组字段销毁——也就是这个字段对数组的引用被移除了,但如果还有其他变量(比如类外部的某个指针、变量)还持有这个数组的引用,引用计数没降到0,内存就不会释放。 - 内存延迟回收的假象:就算数组的引用计数已经归零,Delphi的内存管理器也不会立刻把内存还给操作系统,而是把这块内存放进进程的内存池里留着下次用。这时候你从任务管理器看进程内存,会觉得内存没释放,但实际上内存已经被标记为可复用了。要验证的话,可以用
GetMemoryManagerState获取内存管理器的内部状态,看已分配的块数是不是真的降下来了,别只看系统的进程内存统计。
关于二次运行内存远低于第一次的问题
- 内存池复用是核心原因:第一次运行时,内存管理器得向操作系统申请新的内存块来存数组和字符串;第二次运行时,之前释放的内存还在进程的内存池里,直接拿过来用就行,不用再向操作系统申请新内存,所以进程的内存占用就低很多。这不是编译器优化,是Delphi内存管理器的内存池机制在起作用——哪怕你用的是随机字符串,只要分配的内存块大小和之前的匹配,就会复用池里的内存,所以现象不会变。
- 别混淆字符串常量池:如果是固定字符串,Delphi会用常量池复用,但你用的是随机字符串,这里的复用完全是内存池的功劳,和字符串内容没关系。第一次分配后释放的内存块被标记为可用,第二次分配相同大小的内存时直接复用,自然不会再涨内存。
内容的提问来源于stack exchange,提问作者John John
相关产品推荐
相关产品推荐

