1、线程栈、对象堆
- 线程栈:是栈的数据结构,随着线程分配内存。
- 对象堆:内存,进程中独立画出一块儿内存。因为有些对象不释放,要重用。堆是数组结构
- 值类型:struct类型的都是值类型。
- CLR里的堆是连续分配的(数组),因为空间有限,解约空间
- 操作系统里面,内存是链式分配的,可能有碎片。
2、GC
- 什么时候发生垃圾回收?
当GC new一个对象时会计算占用的空间,如果空间够用则创建对象。如果空间不够用则GC(垃圾回收)。
当程序退出时GC也会发生回收。 - 垃圾回收过程
new的时候发现内存不够,就去根节点(程序入口)遍历访问所有对象,标记访问不到的,然后启动一个线程来清理内存。移除标记了的对象,因为CLR的堆是数组结构,被移除的节点需要补充完整。所以堆需要重新排列,所有线程全部停止,不允许操作内存。 - 析构函数
在GC回收垃圾时,发现带有析构函数的,会把这些对象放入一个队列单独处理,但是不知道在什么时候会调用析构函数。
析构函数是GC回收时CLR主动去调用的,属于被动释放资源。 - 实现IDispose接口(即实现Dispose方法)
主动释放非托管资源,需要自己在方法里写释放资源的代码。也需要我们自己主动去调用这个方法。 - 内存泄漏
内存占用了,没有会收,就会内存泄漏。
2个优化策略
- 分级策略:
- 首次GC前全部对象都是0级
- 第一次GC后,还保留的对象为1级。
- 回收先找0级对象,如果空间不够,再去找1级对象,这之后还存在的对象就为2级
- GC回收0级不够,1级也不够,2级还不够,那就内存溢出了。
- 越是最近被分配的,越是会被回收。
- 大对象策略:
如果大于85k的对象,单独管理,避免频繁移动,存储大对象用的是链表。