Java 和 PHP GC 的差异和差异出现的原因
JAVA 的 GC 处理
判断草死掉的两种方式:引用计数和可达性分析
可达性分析对 JAVA 比较好用的原因是 JAVA遵守这面向对象的严格要求,每个变量都被对象包裹,所以每个变量都能通过对象来进行遍历找到,最终判断他们的是否被引用;
但对于 PHP 这类面向过程下构建的面向对象,找变量引用就比较零碎了,所以主要是引用计数为主;
便捷记忆,在一片空地上,死掉的草都清理(标记清除),就会出现零碎的光秃点,随着秃点增多,将不是秃点的草都挪到新的空地(复制),这样腾出的地和秃点合在一起形成新的空地,有些草活得比较久,有些草活得短,根据查看的频次将活得短的聚合在一起,活得长的聚合在一起,就是分代算法。
Java的垃圾回收(Garbage Collection,GC)机制是一种自动管理内存的技术,它负责检测和清理不再被引用的对象,以释放内存并防止内存泄漏。在Java中,开发人员无需手动释放内存,因为这是由垃圾回收器自动完成的。Java的垃圾回收机制主要基于以下两个原则:
-
引用计数(Reference Counting):这是一种简单的垃圾回收方法,它通过跟踪每个对象的引用计数来确定对象是否可以被回收。当引用计数为零时,对象被认为是不再被引用的,可以被回收。然而,这种方法容易出现循环引用问题,因此在Java中并没有广泛使用。
-
可达性分析(Reachability Analysis):这是Java主要使用的垃圾回收方法。它从根对象(如主方法中的局部变量和静态变量)开始,通过引用链追踪对象是否可以被访问。如果一个对象不再通过任何引用链与根对象相连,那么这个对象就被认为是不可达的,可以被回收。
以下是Java中几种主要的垃圾回收算法:
-
标记-清除算法(Mark and Sweep):
- 这是最基本的垃圾回收算法。
- 首先,它通过可达性分析标记所有可达对象。
- 然后,它扫描整个堆,清理未标记的对象。
- 这个算法的问题是会产生内存碎片,可能会导致堆内存不连续,进而影响程序性能。
-
复制算法(Copying):
- 这个算法将堆内存分为两个区域:一半是已使用的区域,一半是空的。
- 它首先在已使用区域进行标记,然后将存活的对象复制到空区域,最后清理已使用区域。
- 这个算法的优点是避免了内存碎片问题,但需要额外的内存用于复制对象。
-
标记-整理算法(Mark and Compact):
- 这个算法结合了标记-清除和复制算法的优点。
- 首先,它标记可达对象,然后将它们压缩到堆的一端,清理掉堆的另一端的垃圾对象。
- 这个算法也可以减少内存碎片,但不需要额外的内存。
-
分代算法(Generational):
- 这个算法根据对象的年龄将堆分成不同的代。
- 年轻代中的对象通常具有较短的生命周期,老年代中的对象具有较长的生命周期。
- 垃圾回收频繁地发生在年轻代,而较少发生在老年代。
- 这个算法利用了对象的特性,提高了回收效率。
PHP 的 GC 处理
PHP 使用引用计数(Reference Counting)作为主要的垃圾回收机制。每个变量和对象在 PHP 中都有一个引用计数器,用于跟踪对象的引用关系。当一个变量或对象的引用计数降为零时,它就会被认为是不再被引用的,可以被垃圾回收。
以下是 PHP 引用计数垃圾回收机制的基本工作原理:
-
引用计数:每当一个变量或对象引用另一个变量或对象时,引用计数会增加1。当一个变量不再引用某个对象时,引用计数会减少1。这个计数器是实时更新的,反映了对象的当前引用情况。
-
回收不可达对象:垃圾回收器会定期检查引用计数,并找出那些引用计数为零的对象。这些对象被认为是不再被引用的,可以安全地回收内存。
-
循环引用问题:引用计数垃圾回收机制对于循环引用问题并不十分有效。循环引用是指一组对象互相引用,导致它们的引用计数永远不会降为零。为了解决这个问题,PHP 引入了周期性垃圾回收(Cycle Collector),它定期检测并处理循环引用。
-
周期性垃圾回收:周期性垃圾回收器负责检测循环引用,并释放被这些循环引用困住的内存。它会在特定的时间间隔内运行,识别并处理循环引用,从而防止内存泄漏。
Python 的 GC 处理
Python 的垃圾回收(Garbage Collection,GC)机制主要基于引用计数和循环垃圾回收两个核心原理,以自动管理内存。以下是 Python 的垃圾回收机制的详细说明:
-
引用计数(Reference Counting):
- Python 中的每个对象都有一个引用计数器,用于跟踪对象的引用关系。
- 当一个对象被引用时,其引用计数会增加1,当一个对象不再被引用时,其引用计数会减少1。
- 当引用计数降为零时,说明对象不再被任何变量或数据结构引用,可以被垃圾回收。
-
循环垃圾回收:
- 引用计数机制可以有效地处理大多数情况,但对于循环引用(两个或多个对象相互引用形成环)的情况无法处理。
- 为了解决循环引用问题,Python 引入了循环垃圾回收器(Cycle Collector)。
- 循环垃圾回收器定期检查引用关系图,找出并清理不可达的循环引用。
-
分代垃圾回收:
- Python 的垃圾回收还引入了分代垃圾回收策略,将对象分为三代:年轻代、中年代和老年代。
- 大部分新创建的对象放入年轻代,如果在几轮垃圾回收后仍然存活,它们会晋升到中年代,然后到老年代。
- 基于分代的策略利用了对象的生命周期模式,提高了垃圾回收的效率。
-
垃圾回收周期:
- Python 的垃圾回收不是持续运行的,而是在特定条件下触发。
- 垃圾回收器会在一组触发条件满足时运行,如年轻代中对象的数量超过阈值、内存分配请求失败等。
- 当触发条件满足时,垃圾回收器会进行一轮或多轮垃圾回收,清理不可达对象。
-
gc
模块:- Python 提供了一个名为
gc
的模块,用于手动控制和配置垃圾回收机制。 - 开发人员可以使用
gc
模块中的函数来手动触发垃圾回收、禁用垃圾回收或配置垃圾回收参数。
- Python 提供了一个名为
PHP GC 和 Python GC 的差异
PHP 和 Python 是两种不同的脚本语言,它们的垃圾回收(GC)算法和策略存在一些差异。以下是 PHP 和 Python 的 GC 算法之间的主要区别:
PHP 的 GC 算法:
-
引用计数:PHP 主要使用引用计数来管理内存。每个变量和对象都有一个引用计数,当引用计数变为零时,变量或对象就被回收。这个方法简单且实时,但容易出现循环引用问题。
-
周期性垃圾回收:为了解决循环引用问题,PHP 引入了周期性垃圾回收(Cycle Collector)。周期性垃圾回收器会定期检查对象之间的引用关系,以便释放不再使用的内存。这是 PHP 针对循环引用问题的一种补救措施。
-
Zend Memory Manager:PHP 使用 Zend Memory Manager 来管理内存。它负责内存分配和释放,以及跟踪引用计数和垃圾回收。Zend Memory Manager 可以通过配置参数来调整垃圾回收行为。
Python 的 GC 算法:
-
引用计数和循环垃圾回收:Python 同样使用引用计数来追踪对象的引用关系。但与 PHP 不同,Python 还实现了循环垃圾回收器,用于检测并处理循环引用。
-
分代垃圾回收:Python 的垃圾回收还引入了分代垃圾回收策略。Python 将对象分为三代:年轻代、中年代和老年代。新创建的对象会放入年轻代,如果经过一定数量的垃圾回收循环后仍然存活,它们会被提升到中年代,以此类推。这个策略利用了观察到的对象生命周期模式,提高了垃圾回收的效率。
-
垃圾回收周期:Python 的垃圾回收器不是定期运行的,而是基于阈值和触发条件来触发的。具体触发条件包括年轻代对象数量、年轻代空间占用率等。这个策略可以降低垃圾回收对性能的影响。
GO 语言的 GC
Go语言(或简称Golang)的垃圾回收(GC)是一种自动管理内存的机制,旨在减轻开发人员手动管理内存的负担,提高程序的可靠性和性能。Go语言的GC机制具有以下特点和原则:
-
并发垃圾回收:Go语言的GC是并发的,这意味着垃圾回收器可以在程序运行的同时执行。它不会导致应用程序停顿(Stop-The-World),因此对于高并发和实时性要求高的应用程序非常适用。
-
分代垃圾回收:Go语言的GC使用分代垃圾回收策略,将堆内存分为三代:新生代、中年代和老年代。新分配的对象通常放入新生代,存活时间较长的对象会升级到中年代和老年代。这种分代策略提高了垃圾回收的效率。
-
标记-清除算法:Go语言的垃圾回收器使用标记-清除(Mark-and-Sweep)算法。它首先标记所有活动对象,然后清除未标记的对象。这个算法能够处理循环引用并有效地回收不再使用的内存。
-
三色标记法:Go语言的GC引入了三色标记法,将对象标记为白色、黑色和灰色。黑色表示已经标记为活动对象,白色表示未标记的对象,灰色表示待处理的对象。这个方法有助于减少标记和清除的阶段。
-
垃圾回收时间控制:Go语言的垃圾回收器可以通过设置环境变量来控制垃圾回收的时间和频率。这使得开发人员可以根据应用程序的需求进行调整,以平衡性能和内存使用。
-
内存分配优化:Go语言的运行时系统还包括了一个内存分配器,它针对小对象和大对象进行了优化,以减少内存碎片和提高分配性能。
都有哪些场景会用到循环引用?
循环引用是指两个或多个对象之间相互引用,形成一个环形的引用关系。这种情况通常不是有意为之,而是一种错误或者设计不当的情况。尽管循环引用通常是不推荐的,但有一些特定的情景可能需要它们,尤其是在某些编程模型或设计中:
-
数据结构中的循环引用:在某些数据结构中,循环引用是有意为之的。例如,双向链表中的每个节点都包含对前一个和后一个节点的引用,因此它们会形成一个环形引用。这种数据结构在某些情况下非常有用。
-
图数据结构:图是由节点和边组成的数据结构,其中节点之间可能存在循环引用。图数据结构通常用于表示网络、关系和复杂的数据关联。在这种情况下,循环引用是必要的。
-
观察者模式:在观察者模式中,主题对象(Subject)和观察者对象(Observer)之间可能存在循环引用。主题对象需要通知观察者对象进行更新,而观察者对象通常也需要引用主题对象以便取消注册。这种情况下,循环引用是合理的。
-
资源管理:某些资源需要引用它们的持有者。例如,一个对象可能需要引用一个打开的文件、数据库连接或网络连接。这种情况下,资源可能会被多个对象持有,形成循环引用,以确保在没有对象引用资源时不会被关闭。
Javascript 循环引用的一个案例
class Subject {constructor() {this.observers = [];}addObserver(observer) {this.observers.push(observer);}notify(message) {this.observers.forEach(observer => {observer.update(message);});}
}class Observer {constructor(name) {this.name = name;}update(message) {console.log(`${this.name} received message: ${message}`);}
}const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");subject.addObserver(observer1);
subject.addObserver(observer2);observer1.subject = subject; // 主题引用了观察者
observer2.subject = subject;subject.notify("Hello, observers!");
在观察者模式中,观察者通常引用主题对象是为了实现以下目的:
-
访问主题数据:观察者需要访问主题对象的数据或状态以执行相应的操作。通过引用主题对象,观察者可以轻松地获取主题的信息。
-
响应主题的变化:观察者的主要任务是响应主题对象的状态变化。通过引用主题对象,观察者可以注册自己,并接收主题的通知,从而知道何时以及如何更新自己。
-
与主题建立松耦合关系:引用主题对象有助于观察者与主题对象之间建立松耦合的关系。观察者不需要了解主题对象的内部实现细节,只需关注主题的状态变化即可
相关文章:
Java 和 PHP GC 的差异和差异出现的原因
JAVA 的 GC 处理 判断草死掉的两种方式:引用计数和可达性分析 可达性分析对 JAVA 比较好用的原因是 JAVA遵守这面向对象的严格要求,每个变量都被对象包裹,所以每个变量都能通过对象来进行遍历找到,最终判断他们的是否被引用&…...
loguru logger使用
一、基本使用 ①标准使用 from loguru import logger# 在标准输出里面输出一行debug日志 logger.debug("Thats dubug")②设置输出格式 from loguru import loggerlogger.remove(0) # 先删除格式 logger.add(sink./logger.log, format"{time: %Y-%m-%d %H:%M…...
vue-自适应布局-postcss-pxtorem
原理: 比如一个375px设计稿 其中一个320px宽度的元素 如何实现自适应布局呢? 其实可以这样理解: 我们先计算出375屏幕时候320px的大小,在屏幕变化时候,这些元素都会等比例缩放 比如屏幕从375 变为750px时候࿰…...
9.12|day 5|day 44 |完全背包| 518. 零钱兑换 II | 377. 组合总和 Ⅳ
● 完全背包 主要是看清01背包和完全背包的区别 //01背包 for(int i 0;i<weight.size();i){ for(int j bagWeight;j>weight[i];j--){dp[j] Math.max(dp[j],dp[j-weight[i]]value[i]); } } //完全背包 for(int i 0;i<weight.size();i){for(int j weight[i];j<…...
C++ 中的原子变量(std::atomic)使用指南
目录 C 中的原子变量(std::atomic)使用指南基本概念使用方法创建原子变量读取值修改值原子操作 常见应用场景1. 计数器2. 控制标志3. 链表和数据结构 示例代码结论 C 中的原子变量(std::atomic)使用指南 原子变量(std…...
【用unity实现100个游戏之9】使用Unity制作类八方旅人、饥荒风格的俯视角2.5D游戏
前言 2.5D游戏 是一种介于二维和三维之间的游戏形式。它通常在二维平面上展示游戏内容,但利用三维技术来实现更加逼真的图像效果。 在2.5D游戏中,角色和环境通常是以平面的形式呈现,但可以在垂直方向上移动。这意味着玩家可以在一个相对较薄…...
如何在群晖中,正确配置 docker 的 ipv6 地址
参考 2023年9月12日 https://synocommunity.com/ https://github.com/wangliangliang2/fix_synology_docker_ipv6 https://post.smzdm.com/p/an3np8m7/ 正文 关于这个话题,国内搜索引擎得到的结果出奇的一致,且过时。 (看的我脑壳痛&#…...
XSS入门 XSS Challenges
level1(直接注入) <script>alert(xss)</script>level2(双引号闭合标签) 测试 <sCr<ScRiPt>IPT>OonN"\/(hrHRefEF)</sCr</ScRiPt>IPT>发现<>"被转换,构造新的语句 "><script>alert(/xss/)</…...
李沐《动手学深度学习》torch.cat() 和 torch.stack()的区别及思考
一、问题引出 好久没更新啦!最近在学习沐神《动手学深度学习》6.5节池化层的时候,发现沐神在两处相似的地方使用了两种Python拼接函数torch.cat()和torch.stack(): 百思不得其解,于是查阅相关文档之后终于弄清楚了两者之间的区别…...
【算法与数据结构】235、LeetCode二叉搜索树的最近公共祖先
文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析:本题和这道题类似【算法与数据结构】236、LeetCode二叉树的最近公共祖先,相同的算法也能解…...
bboss 流批一体化框架 与 数据采集 ETL
数据采集 ETL 与 流批一体化框架 特性: 高效、稳定、快速、安全 bboss 是一个基于开源协议 Apache License 发布的开源项目,主要由以下三部分构成: Elasticsearch Highlevel Java Restclient , 一个高性能高兼容性的Elasticsea…...
JVM详细教程
JVM 前言 还在完善中先发布 JVM虚拟机厂家多钟多样,具体实现细节可能不一样,这里主要讲的是虚拟机的规范,以下内容融合了各个平台发布的内容和周志明老师的《深入理解java虚拟机》 JVM概述 如何理解jvm跨平台? 编译成汇编代码…...
Smartbi吴华夫:后疫情时代,BI发展趋势的观察与应对
沿着旧地图找不到新大陆,“基于指标体系的可视化分析和增强分析”成为BI发展新阶段。Smartbi V11系列新品与时俱进,以指标为核心,同时融合BI应用,赋能管理者和业务,成为引领数字化运营的新航标! ——思迈特…...
软件设计模式系列之三———工厂方法模式
1 模式的定义 工厂方法模式是一种常见的设计模式,属于创建型设计模式之一,它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化,将具体对象的实例化延迟到子类中完成,以便在不同情况下可以创建不同类型的对…...
pytorch 多卡分布式训练 调用all_gather_object 出现阻塞等待死锁的问题
pytorch 多卡分布式训练 torch._C._distributed_c10d中的函数all_gather_object 出现阻塞等待死锁的问题 解决办法就是 在进程通信之前调用torch.cuda.set_device(local_rank) For NCCL-based processed groups, internal tensor representations of objects must be moved …...
SpringMvc增删改查
SpringMvc增删改查 一、前期准备二、逆向生成增删改查2.2.aspect切面层2.3.Mybatis generator逆向生成2.4.根据生成代码编写Biz层与实现类 三、controller层代码编写四、前台代码与分页代码五、案例测试 一、前期准备 1.2.导入pom.xml依赖 <?xml version"1.0" …...
【计算机网络】网络编程接口 Socket API 解读(5)
Socket 是网络协议栈暴露给编程人员的 API,相比复杂的计算机网络协议,API 对关键操作和配置数据进行了抽象,简化了程序编程。 本文讲述的 socket 内容源自 Linux man。本文主要对各 API 进行详细介绍,从而更好的理解 socket 编程。…...
手动实现一个bind函数!
原文地址:手动实现一个bind函数! - 知乎 1.bind函数用法 bind()方法用于创建一个新的函数,这个新函数接收的第一个参数代表的就是this,利用bind()函数我就就可以任意改变函数内部的this指向了。 官网的解释: bind()…...
数据结构-时间复杂度/空间复杂度
Hello,好久没有更新了哦,已经开始学习数据结构了,这篇文章呢就是对刚学数据结构所接触到的时间复杂度进行一个分享哦,如果有错误之处,大家记得拍拍我哦~ 既然要讨论时间/空间复杂度,那我们就得知道时间/空…...
英语写作中“展示”、“表明”demonstrate、show、indicate、illustrate的用法
一、demonstrate、show、indicate在论文写作中主要用法是:demonstrate/show/indicate 从句: Sb./Sth. demonstrates/shows/indicates that ……从句中一般表达事实、观点和结论等。 例句: The authors demonstrated/showed/indicated that…...
Redis的java客户端
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/resources/clients/ redis的java客户端 https://redis.io/resources/clients/#java 1.jedis使用 引入依赖 <dependency><groupId>redis.clients</groupId><artifac…...
Android环境配置笔记
文章目录 一、各环境文档二、参考 一、各环境文档 Gradle官方的兼容性文档:Java Compatibility 更新日期:2023.9.12 Android Gradle插件版本:Android Gradle Plugin 二、参考 参考文章:Android问题记录...
element-table 行的拖拽更改顺序(无需下载sortableJs
样例展示:vueelement 通过阅读element文档我们发现element并不提供拖拽相关的api 本博客通过element提供的行类名 注册函数 实现行与行的拖拽 1.设置el-table 的行样式类名 这里是用的是 function <el-table:data"outputData":row-class-name&qu…...
Docker部署jenkins
目录 一、jenkins原理二、Docker部署jenkins1.下载jenkins镜像文件2.查看下载的jenkins镜像3.创建Jenkins挂载目录并授权权限4.创建并启动Jenkins容器5.查看jenkins是否启动成功6.查看docker容器日志7.配置镜像加速8.访问Jenkins页面,输入ip地址加上9000端口9.获取管…...
从0到1学会Git(第三部分):Git的远程仓库链接与操作
写在前面:前面两篇文章我们已经学会了git如何在本地进行使用,这篇文章将讲解如何将本地的git仓库和云端的远程仓库链接起来并使用 为什么要使用远程仓库:因为我们需要拷贝我们的代码给别人以及进行协同开发,就需要有一个云端仓库进行代码的存储和同步&a…...
虚拟机Ubuntu操作系统常用终端命令(1)(详细解释+详细演示)
虚拟机Ubuntu操作系统常用终端命令 本篇讲述了Ubuntu操作系统常用的三个功能,即归档,软链接和用户管理方面的相关知识。希望能够得到大家的支持。 文章目录 虚拟机Ubuntu操作系统常用终端命令二、使用步骤1.归档1.1创建档案包1.2还原档案包1.3归档并压缩…...
redis实战-redis实现异步秒杀优化
秒杀优化-异步秒杀思路 未优化的思路 当用户发起请求,此时会请求nginx,nginx会访问到tomcat,而tomcat中的程序,会进行串行操作,分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是否是一…...
Python爬虫-IP隐藏技术与代理爬取
前言 在进行爬虫程序开发和运行时,常常会遇到目标网站的反爬虫机制,最常见的就是IP封禁,这时需要使用IP隐藏技术和代理爬取。 一、IP隐藏技术 IP隐藏技术,即伪装IP地址,使得爬虫请求的IP地址不被目标网站识别为爬虫。…...
二刷力扣--链表
链表 链表类型: 单链表(可以访问后面的一个节点) 双链表(可以访问前后节点) 循环链表(最后一个节点指向首节点) 在Python中定义单链表节点: class ListNode:def __init__(self, v…...
返回值加const ,为了不拷贝得到成员的值,但被赋值的左值也要const
1. getA 函数返回值 什么都不加,也改不了c里面a的指针指向 why?返回成员变量时,会复制一下。 返回成员变量时,一般会赋值一下没有RVO_地摊书贩的博客-CSDN博客 2. getA 函数返回值 加了引用, 就没有复制 3. getA 函数…...
国产做网站/在线bt种子
正式开始转Java了,第一天,语法基础啥的咱都会,直接从做功能开始。先研究怎么用Java连接MySQL吧代码 代码如下复制代码import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;import java.sql.ResultSet;publi…...
建设企业人力资源网站/关键词采集网站
{2015-04-24}接口更新了,暂时用不了了。 再次更新:【2015-4-24 22:13:11】接口链接更新。正常。 function getWeather($city){include weather_code.php;$code$weather_code[$city];//$url"http://tq.360.cn/api/weatherquery/querys?apptq360&am…...
福建住房和城乡建设网站/今日国内最新新闻
Java字符串就是Unicode字符序列,例如“Java”就是4个Unicode字符J,a,v,a组成的。 Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义的类String,每个用双引号括起来的字符串都是String类的一…...
东莞网站建设环保设备/如何开发软件app
某个项目要进行实施工作,购买了50台左右的阿里云的服务器。 ** 由于服务器安全及其他原因,购买了NAT网关。但是在测试配置时,局域网内的所有服务器 ping 公网 ip 都无法 ping 通,但是私网地址所有服务器之间又可以相互ping通。 …...
做购物网站哪个cms好用/seo有名气的优化公司
一、产量 鱼粉是优质的蛋白质原料,广泛应用于水产养殖和高档动物饲料。一般是以鳀鱼为原料,经过蒸煮、压榨、脱脂、脱水、烘干等工序加工后得到的。具有高蛋白、富含各种必须氨基及钙、磷、锌、硒等微量元素,含有未知促生长因子,…...
开建筑公司需要什么条件/优化网站建设seo
项目场景: 在项目实际运用过程中,需要实现Shift点击实现表格多选,以达到表格数据批量操作,如批量选中和批量取消选中。 代码实现 实现代码: <!DOCTYPE html> <html> <head><meta charset"…...