• 垃圾回收


    垃圾[1]回收是一种自动管理内存的方式。通常认为手动内管理[2]与垃圾回收相反。

    就像其他内存管理技术,垃圾回收可能占据大部分程序处理时间,因而对性能有很大影响。

    垃圾回收通常不处理内存之外的资源,比如网络 sockets、数据库 handles、用户交互界面和文件与设备描述符。常用的管理上述资源的方法,尤其是自毁器(destructor)[3],应该足以管理内存,所以不需要垃圾回收(来管理它们)。

    优点

    垃圾回收将程序员从手动回收内存中解放出来。所以对应种类的 bugs 被消除或者大量减少:

    • 野指针[4] bugs,当一片内存被释放而仍然有指针指向它,并且其中一个指针 deference。这时这片内存可能已被重新分配作其它用途,所以可能造成无法预料的结果
    • 两次释放 bugs,程序尝试释放已经被释放的内存区域,而这片内存可能已被重新分配作其它用途,所以可能造成无法预料的结果
    • 内存泄露,程序不能释放无法接触的对象的内存,所以内存占用只会增长而不会减少

    缺点

    • 消耗额外的资源
    • 影响性能,可能导致程序停顿

    垃圾回收消耗计算资源来决定应该释放那些内存,即使程序员已经知道了这个信息。不需要在源码中手动标注对象生存周期的处罚是 overhead[5]。内存层次结构效应[6]会使这个 overhead 在难以预测或常规测试中发现的环境中无法容忍。

    垃圾回收的实际执行时刻是难以预测的,会导致停顿(停顿来转换/释放内存)稀疏地分布在一个任务中。难以预测的停顿在实时环境、事务处理或者交互环境中是无法容忍的。

    策略

    追踪

    追踪垃圾回收是最常见的策略。通过一连串从特定根节点对象的引用来追踪哪些对象是可访问的,并把剩余的(不可访问的)节点视为垃圾并回收它们。

    引用计数

    每个对象有一个引用它的对象数目。引用计数为 0 的对象被视作垃圾。当一个引用它的对象创建时,引用计数加一,当一个引用它的对象销毁时,引用计数减一。

    引用计数保证当引用一个对象(设为 A)的最后一个对象被销毁时,该对象(A)会被销毁,并且通常该内存会位于 CPU 缓存、要被释放的对象或者直接被指向的那些对象中,因此对 CPU 缓存和虚拟内存操作不会有很大的副作用。

    引用计数有很多缺点,但这通常可以通过复杂的算法来解决或者减轻:

    循环引用

    当多个对象互相引用,它们会创建一个循环,因此它们的引用计数不会变为 0。一些垃圾回收系统使用特定的循环检测算法来处理这个问题,比如 CPython。

    另一个策略是创建弱引用。在引用计数中,弱引用不会增加引用对象的引用计数。当一个引用对象被回收时,所有通过弱引用引用其的对象都会被回收。

    空间 overhead

    在引用计数中,需要为每个对象分配空间来储存其引用计数。通常使用无符号指针来做这个事,这意味着要为每个对象分配 32 或 64 位的内存空间。

    速度 overhead

    引用的赋值与回收通常都需要修改一个或多个引用计数器。

    需要原子性

    在多线程环境中,这些修改(增加和减少)可能需要原子操作,至少针对共享的或可能在多线程中共享的对象要这么做。原子操作的代价是很大的,如果使用软件算法模拟,那么代价会更大。

    可以用单线程或单进程来处理引用计数,并且当 local 引用计数变为或不再为 0 时只访问全局引用计数,但这会大大增加内存的负担,因此只在特殊情况下有用(比如 Linux 内核模块)。

    非实时

    Because any pointer assignment can potentially cause a number of objects bounded only by total allocated memory size to be recursively freed while the thread is unable to perform other work.

    参考

    1. 垃圾:未来不会在系统中或(在其上)运行的程序中的内存中的对象、数据或者其他区域。
    2. 手动内存管理:程序员手动使用命令来识别和回收垃圾
    3. 当对象被销毁时自动执行的方法
    4. 没有指向有效对应或者合适类型的指针
    5. 完成一个特定任务所需要的计算时间、内存、宽带或其他资源的过度使用或者路线迂回
    6. 计算机储存基于响应时间被分割为多个层次
  • 相关阅读:
    THINKPHP_(4)_TP模型中with、withJoin和多层关联的深入分析
    THINKPHP_(3)_TP6中实现多层关联,第一个表关联第二个表查询出的数据,再关联第三个表
    THINKPHP_(2)_TP模型的多表关联查询和多表字段的关键字搜索。
    THINKPHP_(1)_修改TP源码,支持对中文字符串按拼音进行排序。
    automapper 源中有多个属性类映射到同一个 目标中
    关于简单的 FluentValidation 验证
    关于SkyApm测试部署。
    linq2db.EntityFrameworkCore 介绍
    关于在CentOS上,绘图丢失部分中文字的问题
    NHibernate入门
  • 原文地址:https://www.cnblogs.com/jay54520/p/8453617.html
Copyright © 2020-2023  润新知