GVKun编程网logo

Python垃圾收集器文档(python垃圾回收器)

16

对于想了解Python垃圾收集器文档的读者,本文将提供新的信息,我们将详细介绍python垃圾回收器,并且为您提供关于CMS垃圾收集器与G1收集器、CPython垃圾收集器检测循环引用详解、java1

对于想了解Python垃圾收集器文档的读者,本文将提供新的信息,我们将详细介绍python垃圾回收器,并且为您提供关于CMS垃圾收集器与G1收集器、CPython 垃圾收集器检测循环引用详解、java 11 新的Epsilon垃圾收集器、java几种垃圾收集方法和垃圾收集器的有价值信息。

本文目录一览:

Python垃圾收集器文档(python垃圾回收器)

Python垃圾收集器文档(python垃圾回收器)

我正在寻找详细描述python垃圾回收如何工作的文档。

我对在哪个步骤中完成操作很感兴趣。这三个集合中有哪些对象?在每个步骤中删除哪些对象?参考循环使用什么算法?

背景:我正在实施一些必须在短时间内完成的搜索。当垃圾收集器开始收集最旧的一代时,它比其他情况“慢很多”。它花费了比计划的更多时间。我正在寻找如何预测何时收集最老的一代以及需要多长时间。

很容易预测何时使用get_count()和收集最老的一代get_threshold()。也可以使用进行操纵set_threshold()。但是我看不出collect()用武力做出更好的决定或等待预定的收集会多么容易。

答案1

小编典典

没有关于Python如何进行垃圾回收的明确资源(除了源代码本身),但是这3个链接应该给你一个很好的主意。

更新资料
来源实际上很有帮助。从中获得多少取决于你对C的理解程度,但是注释实际上非常有帮助。跳到该collect()功能,注释会很好地解释该过程(尽管在技术上非常严格)。

CMS垃圾收集器与G1收集器

CMS垃圾收集器与G1收集器

1、CMS收集器

  CMS收集器是一种以获取最短回收停顿时间为目标的收集器。基于“标记-清除”算法实现,它的运作过程如下:

1)初始标记

2)并发标记

3)重新标记

4)并发清除

  初始标记、从新标记这两个步骤仍然需要“stop the world”,初始标记仅仅只是标记一下GC Roots能直接关联到的对象,熟读很快,并发标记阶段就是进行GC Roots Tracing,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生表动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长点,但远比并发标记的时间短。

 640?wx_fmt=png&wxfrom=5&wx_lazy=1

  CMS是一款优秀的收集器,主要优点:并发收集、低停顿。

缺点:

1)CMS收集器对CPU资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但是会因为占用了一部分线程而导致应用程序变慢,总吞吐量会降低。

2)CMS收集器无法处理浮动垃圾,可能会出现“Concurrent Mode Failure(并发模式故障)”失败而导致Full GC产生。

浮动垃圾:由于CMS并发清理阶段用户线程还在运行着,伴随着程序运行自然就会有新的垃圾不断产生,这部分垃圾出现的标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC中再清理。这些垃圾就是“浮动垃圾”。

3)CMS是一款“标记--清除”算法实现的收集器,容易出现大量空间碎片。当空间碎片过多,将会给大对象分配带来很大的麻烦,往往会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前触发一次Full GC。

2、G1收集器

G1是一款面向服务端应用的垃圾收集器。G1具备如下特点:

1、并行于并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。

2、分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。它能够采用不同的方式去处理新创建的对象和已经存活了一段时间,熬过多次GC的旧对象以获取更好的收集效果。

3、空间整合:与CMS的“标记--清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。

4、可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,

5、G1运作步骤:

1、初始标记;2、并发标记;3、最终标记;4、筛选回收

上面几个步骤的运作过程和CMS有很多相似之处。初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS的值,让下一个阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这一阶段需要停顿线程,但是耗时很短,并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段时耗时较长,但可与用户程序并发执行。而最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remenbered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这一阶段需要停顿线程,但是可并行执行。最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。

640?wx_fmt=png

尾部介绍几个名词:

1,并行(Parallel):多个垃圾收集线程并行工作,此时用户线程处于等待状态 
2,并发(Concurrent):用户线程和垃圾收集线程同时执行 
3,吞吐量:运行用户代码时间/(运行用户代码时间+垃圾回收时间)

面试题:

吞吐量优先和响应优先的垃圾收集器如何选择?

 

(1) 吞吐量优先的并行收集器 
参数配置: 
1, -Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseParallelGC -XX:ParallelGCThreads=8 
说明:选择Parallel Scavenge收集器,然后配置多少个线程进行回收,最好与处理器数目相等。

2,-Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseParallelGC -XX:ParallelGCThreads=8 -XX:+UseParallelOldGC 
说明:配置老年代使用Parallel Old

3,-Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseParallelGC -XX:MaxGCPauseMills=100 
说明:设置每次年轻代垃圾回收的最长时间。如何不能满足,那么就会调整年轻代大小,满足这个设置

4,-Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseParallelGC -XX:MaxGCPauseMills=100 -XX:+UseAdaptiveSizePolicy 
说明:并行收集器会自动选择年轻代区大小和Survivor区的比例。

(2)响应时间优先的并发收集器 
1, -Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 
说明:设置老年代的收集器是CMS,年轻代是ParNew

2,-Xmx4g -Xms4g -Xmn2g -Xss200k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection 
说明:首先设置运行多少次GC后对内存空间进行压缩,整理。同时打开对年老代的压缩(会影响性能)

spark面试顺便问道,Spark Streaming应该选择何种垃圾收集器?

--driver-java-options和 spark.executor.extraJavaOptions这两个参数将driver和Executor垃圾回收器设置为cms,以提高响应速度。

CPython 垃圾收集器检测循环引用详解

CPython 垃圾收集器检测循环引用详解

CPython 中的垃圾收集器

CPython 的垃圾收集器(简称GC)是 Python 内置的为了解决循环引用问题的方法。默认情况下,它总是在后台运行,并且每隔一段时间就会发挥它的魔力,所以你不必担心循环引用物会堵塞你的内存。

垃圾收集器被设计为从 CPython 的工作内存中找到并删除循环引用对象。它通过以下方式完成这一工作。

  • 检测循环引用的对象
  • 调用最终的 __del__ 方法
  • 它从每个对象中删除指针(以此来解决循环问题),只有当循环在步骤 2 之后仍然是孤立的

在这个过程完成后,以前在循环中的每个对象现在的引用计数都是 0 ,因此此对象将从内存中删除。

虽然它是自动工作的,但实际上我们可以把它作为一个模块从标准库中导入。举例如下:

import gc

检测循环引用

CPython 的垃圾收集器会跟踪内存中存在的各种对象--但不是所有的对象。我们可以实例化一些对象,看看垃圾收集器是否会收集它们。

>>> gc.is_tracked("a string")
False
>>> gc.is_tracked(["a", "list"])
True

如果一个对象可以包含指针,这就使它有能力形成循环引用结构的一部分--而这正是垃圾检测器存在的目的,即检测和拆除。在 Python 中这样的对象通常被称为 "容器对象"。

所以,垃圾收集器需要知道任何有可能作为循环引用的一部分而存在的对象。字符串不能,所以 "一个字符串 "不会被垃圾收集器追踪。列表(正如我们已经看到的)能够包含指针,因此 [''a'', ''list''] 被跟踪。

用户定义的类的任何实例也将被垃圾收集器跟踪,因为我们总是可以在它们身上设置任意的属性(指针)。

>>> Wade = MyNameClass("Wade")
>>> gc.is_tracked(Wade)
True

所以,垃圾收集器知道所有有可能形成循环引用的对象。它怎么知道是否已经形成循环引用呢?

它也知道每个对象中的所有指针,以及它们所指向的位置。我们可以看到这个动作。

>>> my_list = ["a", "list"]
>>> gc.get_referents(my_list)
[''list'', ''a'']

get_referents 方法(也称为遍历方法)接收一个对象,并返回它所包含的对象指针的列表(它的引用)。因此,上面的列表包含指向其每个元素的指针,这些元素都是字符串。

让我们在一个对象的循环中看看 get_referents 方法(虽然还不是一个循环引用,因为这些对象仍然可以从命名空间中被访问)。

>>> jane = MyNamedClass("Jane")
>>> bob = MyNamedClass("Bob")
>>> jane.friend = bob
>>> bob.friend = jane
>>> gc.get_referents(bob)
[{''name'': ''bob'', ''friend'': <__main__.MyNamedClass object at 0x7ff29a095d60>}, <class ''__main__

在这个循环中,我们可以看到由 bob 指向的对象包含指向以下内容的指针:它的属性字典,包含 bob 的名字 (bob) 和它的朋友 (同样由 jane 指向的 MyNamedClass 实例) 。bob 对象也有一个指向类对象本身的指针,因为 bob.class 将返回那个类对象。

当垃圾收集器运行时,它检查它所知道的每个对象(也就是当你调用 gc.is_tracked 时返回True的任何对象)是否可以从命名空间到达。它通过跟踪来自命名空间的所有指针,以及这些指针所指向的对象中的指针,以此类推,直到它建立起所有可从代码中访问的东西的整个视图。

如果在做完这些之后,GC 发现存在一些不能从命名空间到达的对象,那么它可以把这些对象清除掉。

记住,任何仍在内存中的对象必须有一个非零的引用计数,否则它们会因为引用计数而被删除。对于那些无法到达但仍有非零引用计数的对象,它们必须是循环引用的一部分,这就是为什么我们如此关心这些发生的可能性。

让我们回到引用循环,jane 和 bob,通过从命名空间中移除指针,把这个循环变成一个循环的隔离。

>>> del jane
>>> del bob

现在,我们已经了解了垃圾收集器所要解决的确切情况。我们可以通过调用 gc.collect() 来触发手动垃圾收集。

>>> gc.collect()
Deleting Bob!
Deleting Jane!
4

默认情况下,垃圾收集器会每隔一段时间自动执行这个动作(因为越来越多的对象在CPython运行时被创建和销毁)。

在上面的代码片段中,我们看到的输出包含了来自 MyNamClass 的 __del__ 方法的打印语句,在最后有一个数字--在这个例子中,是 4。 这个数字是由垃圾收集器本身输出的,它告诉我们有多少对象被移除。

参考链接:

https://anvil.works/articles/pointers-in-my-python-3

以上就是CPython 垃圾收集器检测循环引用详解的详细内容,更多关于CPython 垃圾收集器的资料请关注其它相关文章!

您可能感兴趣的文章:
  • Python解析器Cpython的GIL解释器锁工作机制
  • Cpython解释器中的GIL全局解释器锁
  • 利用一个简单的例子窥探CPython内核的运行机制

java 11 新的Epsilon垃圾收集器

java 11 新的Epsilon垃圾收集器

A NoOp Garbage Collector

JDK上对这个特性的描述是: 开发一个处理内存分配但不实现任何实际内存回收机制的GC, 一旦可用堆内存用完, JVM就会退出.

如果有System.gc()调用, 实际上什么也不会发生(这种场景下和-XX:+DisableExplicitGC效果一样), 因为没有内存回收, 这个实现可能会警告用户尝试强制GC是徒劳.

用法 : -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC

class Garbage {
	int n = (int)(Math.random() * 100);
	@Override
	public void finalize() {
		System.out.println(this + " : " + n + " is dying");
	}
}
public class EpsilonTest {
	
	public static void main(String[] args) {
		boolean flag = true;
		List<Garbage> list = new ArrayList<>();
		long count = 0;
		while (flag) {
			list.add(new Garbage());
			if (list.size() == 1000000 && count == 0) {
				list.clear();
				count++;
			}
		}
		System.out.println("程序结束");
	}
}

如果使用选项-XX:+UseEpsilonGC, 程序很快就因为堆空间不足而退出

使用这个选项的原因 :

提供完全被动的GC实现, 具有有限的分配限制和尽可能低的延迟开销,但代价是内存占用和内存吞吐量.

众所周知, java实现可广泛选择高度可配置的GC实现. 各种可用的收集器最终满足不同的需求, 即使它们的可配置性使它们的功能相交. 有时更容易维护单独的实现, 而不是在现有GC实现上堆积另一个配置选项.

主要用途如下 :

性能测试(它可以帮助过滤掉GC引起的性能假象)

内存压力测试(例如,知道测试用例 应该分配不超过1GB的内存, 我们可以使用-Xmx1g –XX:+UseEpsilonGC, 如果程序有问题, 则程序会崩溃)

非常短的JOB任务(对象这种任务, 接受GC清理堆那都是浪费空间)

VM接口测试

Last-drop 延迟&吞吐改进

原文出处:https://www.cnblogs.com/androidsuperman/p/10351471.html

java几种垃圾收集方法和垃圾收集器

java几种垃圾收集方法和垃圾收集器

标记清除法:

分为两个阶段,标记----清除

标记阶段将所有需要回收的对象做标记,然后在清除阶段将所有的标记对象回收

但是这种回收方法有很大的缺点,那就是这两个过程的的效率并不高,两个过程都是效率很低的过程

另外一个缺点就是标记清除之后,因为之前并没有移动对象,每个标记的对象在空间的各个位置,清除

之后会有很多不连续的内存,在遇到需要分配一个比较大的对象的时候,会出现虽然总量上有空间容纳,

但实际上因为这些内存不连续无法分配一个连续的较大的内存给这个较大对象的情况,而导致系统再次

触发一次GC

复制算法:

复制算法是将空间分为两个大小相等的部分,每次只使用其中的一块,然后这一块用完之后就将自己里面的

还存活着的对象复制到另一块里面去,这样的好处就是清除之后产生的内存不会出现不连续的情况,但缺点

也很明显,那就是需要将内存缩小一半,这样看来这种代价太大,所以之后的复制算法在这上面做出改进,将

内存分为了三个区域,一个Eden区域和两个survivor区域(大小为8/1/1,值得提醒的是这里所说的都是新生代),

将在回收时将Eden区域和其中一个survivor中的存活的对象复制到另一个survivor中,然后将这这两个清理,

相比于1/1的那种复制,显然这种只浪费1/10的的空间,那么这里要问了,其实我当时也提出了这样的问题,假如

存活对象是大于survivor的,那该怎么办,书上给了解释就是需要依赖其他内存来作为担保.细节先不谈,还有就是

这种复制算法,在存活对象比较多的情况下,比如老年代,效率自然就变低.所以产生了接下来这种算法

标记整理算法:

这算法之前的步骤跟第一个标记清除一样,将对象一一标记,但之后不同的是不对对象进行处理,而是将存活对象向一端移动

然后清理另一边的内存,这种算法更适用于老年代

分代收集:

其实就是因地制宜思想,在新生代这种会有大量对象死去的时候,采用复制算法,因为需要复制的内存少,而在老年代

就采用标记清理或者标记整理

 

垃圾收集器

收集算法不止一种,自然收集器也肯定不止一种,不同的收集器作用的范围不同,所采用的算法也不同

如果将作用范围划分为新生代和老年代的话:

连线代表两者能搭配使用,所处区域代表作用范围

依照书上画了一张简易的草图来了解这些收集器的作用范围,然后一一细说

 

Serial收集器

作用域:新生代

采用的收集算法:新生代Serial采用复制算法,老年代SerialOld采用标记整理

特点:单线程收集器,在进行收集的时候,需要暂停其他所有工作线程(Stop the world),简单高效,对于桌面应用场景(新生代使用内存不大)是很好的选择

缺点:在用户不可见的情况下将用户的工作线程都停掉,对其他应用造成影响

 

ParNew收集器

作用域:新生代

算法:新生代复制算法,老年代复制整理算法

特点:是Serial的多线程版本,其余跟Serial一样,是设置-XX:+UserConcMarksSweepGC参数默认的收集器

通过设置jvm参数为-XX:+UserParNewGC来强制使用

 

只有以上两种能与后面出现的并发收集器(CMS)同时工作

 

Parallel Scavenge收集器

作用域:新生代

采用的收集算法:复制算法

特点:多线程收集,关注点跟其他不同,他的目标是得到一个可以控制的吞吐量,即高效利用CPU时间,而其他则是尽可能缩短用户线程的停顿时间,即有良好的相应速度提升用户体验

ps:吞吐量是指运行用户代码时间/(运行用户代码时间和垃圾收集时间)

 

Serial Old收集器 

作用域:老年代

算法:标记整理算法

特点:两大用途,一是jdk1.5之前和与ParallelScavenge一起用,另外就是作为CMS的后备方案

 

Parallel Old收集器

作用域:老年代

特点:注重吞吐量和CPU资源

 

CMS收集器(ConcurrentMarkSweep)

作用域:老年代

算法:标记清除算法

特点:以获取最短回收停顿时间为目标

四个过程:初始标记(标记GCroot能直接关联到的对象,GC管理的主要区域是堆,所以方法区,栈,本地方法区这些不被GC管理的区域的对象一般用于做GCRoots),

并发标记(GC root Tracing),重新标记(修正因为用户操作而标记有变动的对象的标记记录),并发清除,收集过程可以和用户线程并发执行

缺点:-对CPU资源敏感,所以在跟用户进程并发执行的过程中会占用CPU资源导致应用程序变慢,吞吐量降低

-无法处理浮动的垃圾,即在运行过程中产生的垃圾(收集过程中用户进程没有停止,所以垃圾还在产生)

-标记清除,会造成空间碎片化,在大的对象产生时候内存分配会遇到麻烦

 

G1收集器

作用域:

算法:整体标记整理局部复制算法

特点:四大特点:

1,并行与并发,G1能利用多CPU多核心的硬件优势,来缩短STW的时间

2,分代收集

3,空间整合,上面所说的CMS的缺点就是空间碎片化,而G1采用整体标记整理局部复制算法的方法来使得空间的碎片化情况得到解决

4,可预测的停顿,建立了可以预测的停顿时间的模型,能让使用者明确指定一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒

 

感觉这部分知识还需要慢慢啃,一下子搬上来概念或者概述也没啥用...

我们今天的关于Python垃圾收集器文档python垃圾回收器的分享就到这里,谢谢您的阅读,如果想了解更多关于CMS垃圾收集器与G1收集器、CPython 垃圾收集器检测循环引用详解、java 11 新的Epsilon垃圾收集器、java几种垃圾收集方法和垃圾收集器的相关信息,可以在本站进行搜索。

本文标签: