-
2021-02-12 16:08:19
最近整理GC相关原理,发现各种文章都太乱,于是整理一份自己看得懂,不废话,具体如下。
GC主要用于管理JVM的堆区,所以先来介绍一下JVM的内存分配。
1、程序计数器(Program Conuter Register)
程序计数器是一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工作器就是通过改变这个计数器的值来选取下一条需要执行的指令。它是线程私有的内存,也是唯一一个没有OOM异常的区域。
2、Java虚拟机栈区(Java Virtual Machine Stacks)
也就是通常所说的栈区,它描述的是Java方法执行的内存模型,每个方法被执行的时候都创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等。每个方法被调用到完成,相当于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:如果线程请求的栈深度大于虚拟机允许的深度将抛出StackOverflowError;如果虚拟机栈可以动态的扩展,扩展到无法动态的申请到足够的内存时会抛出OOM异常。
3、本地方法栈(Native Method Stacks)
本地方法栈与虚拟机栈发挥的作用非常相似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。
4、堆区(Heap)
所有对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还可以细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为所有线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。
5、方法区(Method Area)
方法区也是所有线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域很少出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,所以也有称这个区域为永久代(Permanent Generation)的。当方法区无法满足内存分配时抛出OOM异常。
6、运行时常量池(Runtime Constant Pool)
运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
针对GC的原理机制,主要搞清楚下面三个问题。
1、什么时候回收?
2、哪些需要回收?
3、怎么回收?
1、什么时候回收?
上面提到GC主要管理的是堆区,堆区主要分为新生代和老年代。大概解释一下这两个区域。
新生代:分为一个Eden和两个Survivor区。新new的对象都放在这里,很快消亡。
老年代:新new的大对象直接丢到这里(为了避免在Eden区和两个Survivor区发生大量的内存拷贝),其余就是在新生代多次回收没被干掉过来变成老家伙的对象了。
①对象优先分配到新生代的Eden区,当不够空间的时候进行一次Minor GC,清理频率很高。
②Full GC发生在老年代,当不够空间的时候进行一次Full GC,伴随着也会进行一次Minor GC。
③进行Minor GC时,会判断每次变成晋升到老年代的对象平均值是否大于老年代剩余空间,如果大于,则进行一次Full GC,如果小于就会去判断HandlePromotionFailure设置是否允许担保失败,如果允许,则进行Minor GC,不允许则改为Full GC。
2、哪些需要回收?
为了下面内容更好理解,首先来了解一下finalize方法。
什么是finalize()方法?
每次进行GC之前系统都会调用一次finalize()方法,用以清理所有活动并且释放资源。
什么时候调用finalize()方法?
1、GC调用之前,例如运行System.gc();(调用System.gc()只是建议JVM去执行,是否执行还得JVM去判断)
2、程序退出时,每个对象都会调用finalzie
3、显式调用finalize
--------------------------------------------------------------------------------------------------------------------------------
引用根搜索算法(GC ROOT Tracing),当一个对象没有任何引用连接的时候,则说明对象不可达,即对象不可用,这个时候就需要进行GC清理。
判断对象是否可达的依据是有没必要执行finalize()方法。如果finalize()方法没有被覆盖或者已经被系统调用过一次了(每个对象生命周期内只能调用一次),则被不可达,需要进行GC清理,否则进行自救,恢复引用连接。
--------------------------------------------------------------------------------------------------------------------------------
3、怎么回收?
不同区域回收算法不同。
新生代:停止-复制。
老年代:标记-清理、标记-整理。
新生代:新生代分为一个Eden区、两个Survivor区(Survivor0、Survivor1)。回收时先把Eden存活对象复制到Survivor0区,清空Eden区,当Survivor0区满了以后,把Eden和Survivor0区的存活对象复制到Survivor1区,清空Eden区和Survivor0区,之后交换Survivor0和Survivor1区,保持Survivor1区是空的,如此往复。
老年代:这两个没什么说的,字面理解。
更多相关内容 -
GC-01-Geiger-Counter:GC-01 Geiger计数器的代码和原理图
2021-03-10 09:39:02GC-01-盖革计数器 GC-01 Geiger计数器的代码和原理图 主程序在src / main.cpp中Gerbers.zip是一个zip文件,其中包含用于PCB制造的gerber文件。 .zip可以直接上载到JLCPCB之类的PCB制造商。 请参阅此链接中的指示信息... -
JVM详解-GC-引用计数法
2020-11-07 19:13:35GC -> 引用计数法 1. GC概述 GC:垃圾回收机制 作用区域: JVM在进行GC时,并不是对堆中的三个区域(新生代、幸存区、老年区)进行统一回收。大部分时候,回收都是在新生代区域。 新生代 幸存区:from ... -
python-gc-prometheus:将有关 Python 应用程序的 GC 统计数据的指标导出到 Prometheus.io
2021-06-10 06:19:36gc stats,它只是导出由模块公开的计数器。 这主要是对象的计数器。 您可以通过导入gc_prometheus.stats单独导入这些指标。 gc profiling stats,它向 gc 模块注册回调并向垃圾收集过程添加一些可以忽略不计的开销... -
04_程序计数器.pptx
2021-05-21 01:04:56程序计数器 -
Java高效计数器
2021-03-05 15:01:25翻译人员: 铁锚翻译时间: 2013年11月3日原文链接: Efficient Counter in Java我们经常使用 HashMap作为计数器(counter)来统计数据库或者文本中的某些东西.本文将使用HashMap来实现计数器的3种不同方式进行对比。1. ...翻译人员: 铁锚
翻译时间: 2013年11月3日
原文链接: Efficient Counter in Java
我们经常使用 HashMap作为计数器(counter)来统计数据库或者文本中的某些东西.
本文将使用HashMap来实现计数器的3种不同方式进行对比。
1. 新手级计数器
如果使用这一类别的计数器,那么代码大致如下所示:
String source = "my name is name me and your name is her first her";
String[] words = source.split(" ");
// 新手级计数器
public static void testNaive(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
if(counter.containsKey(w)){
int oldValue = counter.get(w);
counter.put(w, oldValue+1);
} else {
counter.put(w, 1);
}
}
}
在每次循环中,判断是否包含了相应的key,如果包含,那么值在原来的基础上加1,如果没有,那就设置为1.
此种方式简单又直接,但并不是很有效率。效率不高的原因如下:
1.1 当一个key存在时,containsKey() 和 get() 分别调用了一次,这意味着对map进行了两次查找。
1.2 因为 Integer 是不可变的,每次循环在增加计数值的时候将会创建一个新的对象.
2. 入门级计数器
那么我们自然需要使用一个可变的整数来避免创建太多个Integer对象.可变整数类可以如下面所示来定义:
// 可变Integer
public static final class MutableInteger{
private int val;
public MutableInteger(int val){
this.val = val;
}
public int get(){
return this.val;
}
public void set(int val){
this.val = val;
}
// 为了方便打印
public String toString() {
return Integer.toString(val);
}
}
那么计数器可以用如下的方式来改进:
// 入门级计数器
public static void testBetter(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
if(counter.containsKey(w)){
MutableInteger oldValue = counter.get(w);
oldValue.set(oldValue.get()+1);// 因为是引用,所以减少了一次HashMap查找
} else {
counter.put(w, new MutableInteger(1));
}
}
}
因为不需要创建太多的Integer对象,看起来好了一些。然而,key存在的情况下,每次循环依然要进行两次查找.
3. 卓越级计数器
HashMap 的 put(key,value) 方法会返回key对应的当前value.了解这个特性,我们可以利用原有值来进行递增,并不需要多次的查找.
public static void testEfficient(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
MutableInteger initValue = new MutableInteger(1);
// 利用 HashMap 的put方法弹出旧值的特性
MutableInteger oldValue = counter.put(w, initValue);
if(oldValue != null){
initValue.set(oldValue.get() + 1);
}
}
}
4. 性能差异
为了测试这三种实现方式的性能,采用了下面的代码。先看看结果如何,性能测试分别执行了多次,对每一个数量级的测试,误差不算太大,所以取其中的一个结果排列如下:
10000000 次循环:
新手级计数器: 7726594902
入门级计数器: 6516014840
卓越级计数器: 5736574103
1000000 次循环:
新手级计数器: 777480106
入门级计数器: 642932000
卓越级计数器: 571867738
100000 次循环:
新手级计数器: 84323682
入门级计数器: 70176906
卓越级计数器: 61219664
10000 次循环:
新手级计数器: 13279550
入门级计数器: 7874100
卓越级计数器: 6460172
1000 次循环:
新手级计数器: 4542172
入门级计数器: 2933248
卓越级计数器: 992749
100 次循环:
新手级计数器: 3092325
入门级计数器: 1101695
卓越级计数器: 423942
10 次循环:
新手级计数器: 1993788
入门级计数器: 558150
卓越级计数器: 153156
1 次循环:
新手级计数器: 1625898
入门级计数器: 427494
卓越级计数器: 69473
从上面的输出可以看到,10000次的时候, 13:8:6 秒,相差很明显.特别是 新手级计数器和入门级计数器之间的比例,这说明创建对象是很耗资源的操作。
当然,次数更多的差距不明显的原因在于,触发了多次的GC垃圾回收,同时也证明了垃圾回收的代价确实很大。
完整的测试代码如下:
import java.util.HashMap;
public class TestCounter {
public static void main(String[] args) {
// 源字符串
String source = "my name is name me and your name is her first her";
// 计时,单位: 微秒
long startTime = 0;
long endTime = 0;
long duration = 0;
// 测试次数
int loop = 1 * 10000;
System.out.println(loop +" 次循环:");
startTime = System.nanoTime();
testNaive(source,loop);
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("新手级计数器: " + duration);
//
startTime = System.nanoTime();
testBetter(source, loop);
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("入门级计数器: " + duration);
//
startTime = System.nanoTime();
testEfficient(source, loop);
endTime = System.nanoTime();
duration = endTime - startTime;
System.out.println("卓越级计数器: " + duration);
}
// 新手级计数器
public static void testNaive(String source, int loop){
if(null == source){
return;
}
//
String[] words = source.split(" ");
for (int i = 0; i < loop; i++) {
testNaive(words);
}
}
public static void testNaive(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
if(counter.containsKey(w)){
int oldValue = counter.get(w);
counter.put(w, oldValue+1);
} else {
counter.put(w, 1);
}
}
}
// 可变Integer
public static final class MutableInteger{
private int val;
public MutableInteger(int val){
this.val = val;
}
public int get(){
return this.val;
}
public void set(int val){
this.val = val;
}
// 为了方便打印
public String toString() {
return Integer.toString(val);
}
}
// 入门级计数器
public static void testBetter(String source, int loop){
if(null == source){
return;
}
//
String[] words = source.split(" ");
for (int i = 0; i < loop; i++) {
testBetter(words);
}
}
public static void testBetter(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
if(counter.containsKey(w)){
MutableInteger oldValue = counter.get(w);
oldValue.set(oldValue.get()+1);// 因为是引用,所以减少了一次HashMap查找
} else {
counter.put(w, new MutableInteger(1));
}
}
}
// 卓越级计数器
public static void testEfficient(String source, int loop){
if(null == source){
return;
}
//
String[] words = source.split(" ");
for (int i = 0; i < loop; i++) {
testEfficient(words);
}
}
public static void testEfficient(String[] words){
HashMap counter = new HashMap();
for (String w : words) {
MutableInteger initValue = new MutableInteger(1);
// 利用 HashMap 的put方法弹出旧值的特性
MutableInteger oldValue = counter.put(w, initValue);
if(oldValue != null){
initValue.set(oldValue.get() + 1);
}
}
}
}
当你实用计数器的时候,很可能也需要根据值来进行排序的方法,请参考: the frequently used method of HashMap.
5. Keith网站评论列表
我觉得最好的评论如下:
添加了三个测试:
1) 重构了 “入门级计数器”,不使用containsKey,改为只使用get方法. 通常你需要的元素是存在于 HashMap 中的, 所以将 2 次查找精简为 1次.
2) 作者 michal 提到过的方式,使用 AtomicInteger来实现 .
3) 使用单个的int 数组来进行对比,可以使用更少的内存,参见 http://amzn.com/0748614079
我运行了测试程序3次,并挑选出最小的那个值(以减少干扰). 注意: 你不能在程序中让运行结果受到太多干扰,因为内存不足可能会受到gc垃圾回收器太多的影响.
新手级计数器: 201716122
入门级计数器: 112259166
卓越级计数器: 93066471
入门级计数器 (不使用 containsKey): 69578496
入门级计数器 (不使用 containsKey, with AtomicInteger): 94313287
入门级计数器 (不使用 containsKey, with int[]): 65877234
入门级计数器 (不使用 containsKey 方法:):
HashMap efficientCounter2 = new HashMap();
for (int i = 0; i < NUM_ITERATIONS; i++)
for (String a : sArr) {
MutableInteger value = efficientCounter2.get(a);
if (value != null) {
value.set(value.get() + 1);
}
else {
efficientCounter2.put(a, new MutableInteger(1));
}
}
入门级计数器 (不使用 containsKey, 使用 AtomicInteger):
HashMap atomicCounter = new HashMap();
for (int i = 0; i < NUM_ITERATIONS; i++)
for (String a : sArr) {
AtomicInteger value = atomicCounter.get(a);
if (value != null) {
value.incrementAndGet();
}
else {
atomicCounter.put(a, new AtomicInteger(1));
}
}
入门级计数器 (不使用 containsKey, 使用 int[]):
HashMap intCounter = new HashMap();
for (int i = 0; i < NUM_ITERATIONS; i++)
for (String a : sArr) {
int[] valueWrapper = intCounter.get(a);
if (valueWrapper == null) {
intCounter.put(a, new int[] { 1 });
}
else {
valueWrapper[0]++;
}
}
Guava 语言的 MultiSet 可能更快一些.
6. 结论
优胜者是使用int数组的方式.
参考文章
HashMap.put() HashMap.put()
相关阅读
1. ArrayList vs. LinkedList vs. Vector
Frequently Used Methods of Java HashMap
-
计数器(Counter)
2021-03-15 03:52:28Hadoop中的计数器有点类似于日志,可以输出Hadoop在运行过程的运运算信息。在之前运行的WordCount中,控制台输出的信息有以下内容(可以再运行一次WordCount案例进行查看):Counters:38FileSystemCounters#10个FILE:...Hadoop中的计数器有点类似于日志,可以输出Hadoop在运行过程的运运算信息。
在之前运行的WordCount中,控制台输出的信息有以下内容(可以再运行一次WordCount案例进行查看):Counters: 38
File System Counters #10个
FILE: Number of bytes read=462
FILE: Number of bytes written=541399
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=38
HDFS: Number of bytes written=19
HDFS: Number of read operations=15
HDFS: Number of large read operations=0
HDFS: Number of write operations=6
Map-Reduce Framework #20个
Map input records=2
Map output records=4
Map output bytes=35
Map output materialized bytes=49
Input split bytes=109
Combine input records=0
Combine output records=0
Reduce input groups=3
Reduce shuffle bytes=49
Reduce input records=4
Reduce output records=3
Spilled Records=8
Shuffled Maps =1
Failed Shuffles=0
Merged Map outputs=1
GC time elapsed (ms)=59
CPU time spent (ms)=0
Physical memory (bytes) snapshot=0
Virtual memory (bytes) snapshot=0
Total committed heap usage (bytes)=242360320
Shuffle Errors #6个
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters #1个
Bytes Read=19
File Output Format Counters #1个
Bytes Written=19
可以看到输出的日志中,提示总共有38个计数器,分成了5组,File System Counters等称之为组名,可以看出每组分别有10、20、6、1、1个计数器。
对于这38个计数器,我们并不是每一个都关心,以下重点讲解部分计数器的作用
一、计数器讲解
1、File Input Format CountersFile Input Format Counters #1个
Bytes Read=19
表示的是我们从HDFS中读取的文件的字节数总共是19个字节
回归之前的word.txt中的文本内容hello you
helo me
5+3+5+2=15,加上2个空格和一个换行,一个结束符也是19个字符。
2、Map-Reduce FrameworkMap-Reduce Framework #20个
Map input records=2
Map output records=4
Map output bytes=35
Map output materialized bytes=49
Input split bytes=109
Combine input records=0
Combine output records=0
Reduce input groups=3
Reduce shuffle bytes=49
Reduce input records=4
Reduce output records=3
Spilled Records=8
Shuffled Maps =1
Failed Shuffles=0
Merged Map outputs=1
GC time elapsed (ms)=59
CPU time spent (ms)=0
Physical memory (bytes) snapshot=0
Virtual memory (bytes) snapshot=0
Total committed heap usage (bytes)=242360320
Map input records=2hello you
hello me
刚好是2行
Map output records=4
由于我们的mapper中,是每读取一个单词,就输出一个键值对,因此map任务的输出是:,
,
,
刚好有四个
Reduce input records=4
map输出的记录就是reduce输入的记录数,因此也是四个
Reduce input groups=3
关于分组group的概念我们之后会详细讲解,实际上就是将mapper的输出的记录进行分组,即把相同key的分为一组,所以分组后是
刚好分成3组。
Reduce output records=3
WordCount案例中的输出为hello 2
you 1
me 1
刚好是3行。
Combine input records=0、Combine output records=0
这是属于规约,在后面我们会详细的讲解规约的概念。
二、自定义计数器
计数器用Counter对象表示,每个计数器都有一个组,只要组名(groupName)相同,那么这些计数器就自动属于一个组。并且每个计数器还有这自己的名字(counterName),用以区分同一个组下的不同计数器。
获得一个计数器实例的方法如下:Counter counter = context.getCounter(groupName, counterName);
例如,我们现在要进行敏感词统计,即分析某段文本内容中出现了多少次敏感词。假设我们把"hello"认为是一个敏感词。在WordCount案例的基础上,我们可以将TokenizerMapper的代码修改如下public static class TokenizerMapper extends
Mapper {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
@Override
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// StringTokenizer是java工具类,将字符串按照空格进行分割
StringTokenizer itr = new StringTokenizer(value.toString());
//自定义计数器
String groupName="Custom Group";//
String counterName="Sensitive words";
Counter counter = context.getCounter(groupName, counterName);
// 每次出现一个单词,单词次数加1
while (itr.hasMoreTokens()) {
String nextToken = itr.nextToken();
if(nextToken.equals("hello")){//假设"hello"为敏感词,每次输出,即加1
counter.increment(1);
}
word.set(nextToken);
context.write(word, one);
}
}
}
再次运行WordCount案例,我们可以看到控制台中输出了我们自定义的计数器Counters: 39
File System Counters
FILE: Number of bytes read=462
FILE: Number of bytes written=541399
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=38
HDFS: Number of bytes written=19
HDFS: Number of read operations=15
HDFS: Number of large read operations=0
HDFS: Number of write operations=6
Map-Reduce Framework
Map input records=2
Map output records=4
Map output bytes=35
Map output materialized bytes=49
Input split bytes=109
Combine input records=0
Combine output records=0
Reduce input groups=3
Reduce shuffle bytes=49
Reduce input records=4
Reduce output records=3
Spilled Records=8
Shuffled Maps =1
Failed Shuffles=0
Merged Map outputs=1
GC time elapsed (ms)=38
CPU time spent (ms)=0
Physical memory (bytes) snapshot=0
Virtual memory (bytes) snapshot=0
Total committed heap usage (bytes)=242360320
Custom Group #我们自定义的组名
Sensitive words=2 #我们自定义的计数器的值为2
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=19
File Output Format Counters
Bytes Written=19
-
4.7 JAVA计数器
2021-03-09 20:35:29你也许经常需要一个计数器来了解数据库或文本文件中一些事务出现的频率(例如单词)。通过在Java中计数器可以通过HashMap可以轻松实现计数器。本文比较了实现不同的计数器方法。更新: 查看Java8 计数器,写一个计数器... -
JVM的分区+查看GC对象是否存活+3种GC算法+7种垃圾收集器+如何减少GC次数
2021-02-27 20:27:10一、JVM的分区:1、程序计数器(私有)程序计数器是一块较小的内存分区,你可以把它看做当前线程所执行的字节码的指示器。在虚拟机的概念模型里,字节码解释器工作时,就是通过改变计数器的值来选择下一条需要执行的... -
php引用计数器进行垃圾收集机制介绍
2021-01-21 15:50:08垃圾收集的内部方式是使用一个引用计数器,因此当计数器达到 0 时(意味着对该对象的引用都不可用),对象将被当作垃圾收集并从内存中删除。 每一种计算机语言都有自己的自动垃圾回收机制,让程序员不必过分关心程序... -
怎么解决引用计数 GC 的循环引用问题?
2021-03-08 08:55:07作者:Android面试官引用计数方式 GC 存在循环引用问题,导致无法辨别无用对象,而 GC ROOT 方式不存在循环引用的问题引用计数和 GC ROOT 的实现机理很易理解,面试时大家都能流利应答,那怎么才能脱颖而出呢?... -
程序计数器没有OOM
2021-03-15 16:56:18程序计数器(Program Counter Register)也称PC寄存器。是运行时数据区里唯一一块没有Out of Memory的区域。 只存下一个字节码指令的地址,消耗内存小且固定,无论方法多深,他只存一条。 只针对一个线程,随着线程... -
JVM内存管理及GC原理调优实战
2020-12-22 08:26:03在去做这项工作前就必须去了解JVM是怎么去管理内存的,GC是怎么完成的。 二、标记算法 垃圾回收是对已经分配出去的但又不再使用的内存进行回收,以便能够再次分配。JVM主要是对堆空间那些死亡对象所占据的空间进行... -
JVM GC回收算法-引用计数法和可达性分析法
2018-07-08 15:20:43尤其是GC算法。程序计数器、虚拟机栈、本地方法栈。这几个区域完全不用管回收问题,因为方法结束或者线程结束的时候他们所占用的内存就自然跟着一起释放了,3个区域随线程而生,随线程而灭。所以我们只需要管堆和... -
【JVM(内存与垃圾回收)】程序计数器,程序计数器使用举例,程序计数器两个面试问题
2021-07-10 14:55:091.程序计数器: 程序计数器介绍: 方法区,堆有GC,有OOM,本地方法栈,虚拟机栈有栈溢出,没有GC,程序计数器没有GC,没有OOM 2.程序计数器使用举例: 3.程序计数器两个面试问题: -
图解GC(垃圾回收)引用计数法
2021-01-27 18:40:12引用计数法(Reference Counting) 由1960年GeorgeE.Collins提出。引用计数法为每个对象引入...缺点:1,计数器增减运算繁重,代码实现复杂,实现复制就意味着容易产生BUG。2,典型的引用计数器需要占更多bit。3,循 -
Java GC工作原理以及Minor GC、Major GC、Full GC、GC收集相关算法整理
2018-08-16 10:42:04名词解释: GC:垃圾收集器 Minor GC:新生代GC,指发生在新生代的垃圾...Major GC/Full GC:老年代GC,指发生在老年代的GC。 JVM:Java Virtual Machine(Java虚拟机)的缩写。 正文: >堆 众所... -
MapReduce中的计数器概念和自定义计数器方法
2019-11-16 09:30:25计数器的概念 打个比方:人数钱的时候,人就是计数器 计数器是收集作业统计信息的有效手段之一,用于质量控制或应用级统计(就是用来数数的)。 计数器还可辅助诊断系统故障。如果需要将日志信息传输到map 或reduce... -
深入理解Java-GC机制
2018-04-13 15:28:14今天我们来谈谈Java主流虚拟机-HotSpot的GC实现机制,本篇文章默认使用HotSpot虚拟机进行介绍,如果没有特殊说明,其都为HotSpot虚拟机中的特性。 Java与C++之间有一堵由内存动态分配和垃圾收集技术所围城的“高墙... -
深入理解Java GC
2021-02-12 11:02:38我们从这几方面介绍GC机制。什么是GC,GC在什么时候,对什么东西,做了什么事情。常用的GC算法有哪些为什么要把堆分代?我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代... -
GC之引用计数算法
2019-09-25 18:38:24我们都知道c++程序在...引用计数算法是为每个对象一个计数器用来保存对象被引用的次数,如果该对象被其他对象引用,计数器加1,对该对象引用结束则计数器减1,当计数器为0时认为该对象已经没有任何引用,就会被回... -
程序计数器(PC寄存器)
2022-01-29 00:06:54程序计数器(PC寄存器)PC RegisterPC寄存器使用举例常见面试问题CPU时间片 PC Register JVM中的程序计数寄存器(Program Counter Register)中,Register 的命名源于CPU的寄存器,寄存器存储指令相关的现场信息。CPU... -
JVM内存管理及GC机制
2021-12-06 21:42:40Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。... -
java8 各种GC的总结
2021-08-11 17:17:21给对象添加一个引用计数器,当有一个地方引用时,计数器就加1,当引用失效时,计数器就减1。任何时刻只要计数器为0则回收。但是这种算法无法解决对象之间互相循环引用的问题。如A引用B,而B又引用A,计数器永远不为0... -
g1gc调优的一次实战记录
2021-10-24 21:00:50程序计数器 虚拟机栈 本地方法栈 GC算法 1,标记 -清除算法 2,复制算法 3,标记-压缩算法 4,分代收集算法 一般将堆分为新生代和老年代。 新生代使用: 复制算法 老年代使用: 标记 - 清除 或者 标记 - 整理 算法 ... -
内存分配与回收策略及MinorGC、MajorGC、FullGC介绍
2019-09-08 16:14:43MinorGC、MajorGC、FullGC的定义区别和触发条件;还有通过图示展示了GC的过程。 目录 对象内存分配与回收策略 对象何时进入新生代、老年代 三种GC介绍 MinorGC Major GC/Full GC: 图示GC过程 对象内存分配... -
【Java 虚拟机原理】垃圾回收算法 ( Java 虚拟机内存分区 | 垃圾回收机制 | 引用计数器算法 | 引用计数循环...
2021-09-03 10:51:04一、Java 虚拟机内存分区、 二、垃圾回收机制、 三、引用计数器算法 ( 无法解决循环引用问题 )、 -
JVM(三)程序计数器【PC寄存器】
2021-02-28 07:20:04PC Register介绍JVM中的程序计数器(Program Counter Register),Resgiter 的命名原于CPU的寄存器,寄存器存储指令相关的现场信息。CPU只有把数据装载到寄存器才能够运行。这里,并非是广义所指的物理寄存器,或许将... -
如何强制GC回收垃圾
2021-02-12 20:31:19Java垃圾回收机制(GC)详解简介:垃圾回收GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变... -
JVM中的程序计数器
2022-04-09 18:58:52先来看一下JVM的体系结构,在java虚拟机中有一块非常重要的区域———...而程序计数器就处于这块区域中。 程序计数器是执行速度最快的内存区域,它相当于交通警察,当jvm将类等相关的信息加载进运行时数据区后, ...