垃圾回收以及内存管理机制

内存管理机制

所有公司都会遇到两个最难处理,最恶心的问题:

  • 高并发问题
  • 内存泄漏问题(例:比如一个大袋子可以装100斤大米,但是却装了200斤大米。虽然我们可以在换个袋子,但是袋子里的大米却不好捡起来)
    • 所以公司一般都会有一套容灾系统:
      • 程序崩了,瞬间切换到另一台服务器让它跑起来,数据一般都不会放在同一台服务器上
    • 我有1个G的内存,一个游戏需要800M的内存,其他的需要300M的内存,它们都互相竞争资源,其写的不让写,游戏想写写不进去,就崩了。现在的程序就是内存快满了,就会回收一些你不用的,把空间省下来。
  • python的就是垃圾回收机制

垃圾回收机制

在python源码中,ob_refcnt记录了对象的引用次数。当一个对象有新的应用时,ob_refcnt加一,引用它的对象被删除时,ob_refcnt=0,这个对象的生命就结束了,这时,垃圾回收机制就会启动将这个对象回收。

类执行完毕后会自动调用__del__方法,进行垃圾回收

什么时候回收(回收时机):

1、隔断时间自动回收

2、内存不够了回收

3、主动调用gc
gc.collect()

python是引用计数为主,标记清除+分代回收为辅

程序如何判断是否是垃圾:

1、引用计数
2、标记清楚+分代回收

引用计数

优点:

  • 简单、易可用
  • 实时性高,只要对象引用计数为0,对象就会被销毁,内存被释放,回收内存的时间平摊到了平时
    缺点:
* 为了维护引用计数消耗了很多资源
* 循环引用,循环引用导致内存泄漏,例:
>>> class lia(list):
...     def __del__(self):
...             print('a销毁')
...
>>> class lib(list):
...     def __del__(self):
...             print('b销毁')
>>> a= lia()
>>> b = lib()
>>> a.append(b)	# 循环引用
>>> b.append(a)
# 会发现没有触发del方法
>>> a = 2
>>> b = 3

这样就会导致list1和list2的引用计永远大于0,除非手动操作,他们也不可能被GC回收,但如果你手动将其释放回收,那么GC机制岂不是形同虚设,针对这种情况,python引入了标记清除和分代回收机制作为补充

标记清除

  • 从变量出发,看你这个变量用到了哪些东西,用到了就留着。如果从头到尾发现某些数据没有被使用过,这个数据就是垃圾。
  • 解决的就是循环引用的问题
  • 弊端:浪费时间(执行速度比较慢),cpu资源
标记清除的原理:

标记清除可以处理这种循环引用的情况,它分为两个阶段

  • 第一阶段,标记阶段
    • GC会把所有活动对象打上标记,这些活动的对象就如同一个点,他们之间的引用关系构成边,最终点边构成了一个有向图
  • 第二阶段,搜索清除阶段
    • 从跟对象(root)触发,沿着有向边遍历整个图,不可达的对象就时需要清理的垃圾对象,这个根对象就是全局对象,调用栈,寄存器
分代回收
  • 解决的就是标记清楚所引发的问题

  • 分代回收建立标记清楚的基础之上,是一种以空间换时间的操作方式。标记清楚可以回收循环引用的垃圾,但是,回收的频次是需要控制的,如果时时刻刻做标记清楚,可以想象,python的程序会慢成什么样子。

  • 分代回收,根据内存中对象的存活时间将他们分为3代,新生的对象放入到0代,如果一个对象能在第0代的回收过程中存活下来,GC就会将其放入到1代中,如果1代里的对象在第1代的垃圾回收过程中存活下来,则会进入到第2代。

触发机制
import gc
print(gc.get_threshold())	# (700,10,10)
  • 当分配对象的个数减去释放对象的个数的差值大于700时,就会产生一次0代(青年代)回收
  • 10次0代回收会导致一次1代(中年代)回收
  • 10次1代回收会导致一次2代(老年代)回收
    对于0代的对象来说,他们很可能就被使用一次,因此需要经常被回收

经过第0代的对象来说,他们很可能就被使用一次,因此需要经常被回收。

经过一轮一轮的回收后,能过存活着成为第二代的对象,必然时那些使用频繁的对象,而且他们以及存活很久的时间了,大概率的,还会存活很久,因此,2代回收的就不那么频繁

你可以设置这三个阈值,来改变分代回收的触发条件

import gc

# 设置使0代和2代的回收更加频繁
gc.set_threshold(600, 10, 5)
print(gc.get_threshold())

例如:
有1000个对象·,销毁了1000个对象,还有900个对象,大于700,担心900个对象里面有大量的垃圾对象,所以就进行一次0代回收,在0代回收存活的对象,一般还能存活很久。在0代回收的对象,就会放入到1代当中。当进行10次1代回收之后,就会进入2代回收

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合
Java堆内存是Java虚拟机(JVM)中用于存储对象实例的主要区域。垃圾回收(Garbage Collection, GC)机制是Java设计的核心特性之一,它负责自动管理和回收不再使用的内存,以防止内存泄漏和内存溢出。Java堆内存的垃圾回收主要包括以下几个关键概念和过程: 1. **可达性分析**:GC通过可达性分析确定哪些对象是“活着”的。如果一个对象能通过当前存在的引用路径到达,那么它是可达的,否则就是垃圾。 2. **标记-清除算法**:从根对象(如静态变量、本地方法栈引用的对象)开始,标记所有可达的对象,然后清除未标记的对象。这个过程中可能会产生内存碎片。 3. **复制算法**:将堆分为两个部分,每次只使用一部分,使用完毕后把存活的对象复制到另一部分,然后清除旧的部分。这种方法避免了碎片化,但空间效率较低。 4. **标记-整理算法**:标记垃圾对象后,将存活对象向一端移动,腾出的空间整理为连续区域,便于后续内存分配。 5. **分代回收**:根据对象生命周期的不同,分为新生代(短生命周期的对象)和老年代(长生命周期的对象)。新生代采用 Minor GC,老年代则进行 Major GC,这有助于优化回收性能。 6. **引用计数**:虽然Java不直接使用引用计数,但在某些情况下(如JNI环境),引用计数也可能被用作辅助机制。 **相关问题--:** 1. Java堆内存的垃圾回收频率由哪个参数控制? 2. 如何避免新生代的内存溢出? 3. 什么是GC Roots?它们在可达性分析中的作用是什么?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值