- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
相信大多数人的理解是Major GC只针对老年代,Full GC会先触发一次Minor GC,不知对否?我参考了R大的分析和介绍,总结了一下相关的说明和分析结论.
针对HotSpot VM的实现,它里面的GC其实准确分类只有两大种:
Partial GC代表着并不收集整个GC堆的模式 。
Full GC代表着收集整个JVM的运行时堆+方法区+直接堆外内存的总体范围内。(甚至可以理解为JVM进程范围内的绝大部分范围的数据区域).
它会涵盖了所有的模式和区域包含:Young Gen(新生代)、Tenured Gen(老生代)、Perm/Meta Gen(元空间)(JDK8前后的版本)等全局范围的GC垃圾回收模式.
在一般情况下Major GC通常是跟Full GC是等价的,收集整个GC堆。但如果从HotSpot VM底层的细节出发,如果再有人说“Major GC”的时候一定要问清楚他想要指的是上面的Full GC还是Old/Tenured GC.
按HotSpot VM的Serial GC的实现来看,当Young gen中的Eden区分达到阈值(属于一定的百分比进行控制)的时候触发.
注意:Young GC中有部分存活对象会晋升到Old/Tenured Gen,所以Young GC后Old Gen的占用量通常会有所升高 .
当准备要触发一次Young GC时,如果发现统计数据说之前Young Old/Tenured Gen剩余的空间大,则不会触发Young GC,而是转为触发Full GC(因为HotSpot VM的GC里,除了CMS的Concurrent collection之外,其它能收集Old/Tenured Gen的GC都会 同时收集整个GC堆 ,包括Young gen,所以不需要事先触发一次单独的Young GC); 。
如果有Perm/Meta gen的话,要在Perm/Meta gen分配空间但已经没有足够空间时,也要触发一次full GC.
System.gc()方法或者Heap Dump自带的GC,默认也是触发Full GC。HotSpot VM里其它非并发GC的触发条件复杂一些,不过大致的原理与上面说的其实一样.
注意:Parallel Scavenge(-XX:+UseParallelGC)框架下,默认是在要触发Full GC前先执行一次Young GC,并且两次GC之间能让应用程序稍微运行一小下,以期降低Full GC的暂停时间(因为young GC会尽量清理了Young Gen的垃圾对象,减少了Full GC的扫描工作量)。控制这个行为的VM参数是-XX:+ScavengeBeforeFullGC.
Concurrent GC的触发条件就不太一样。以CMS GC为例,它主要是定时去检查Old Gen的使用量,当使用量超过了触发比例就会启动一次CMS GC,对Old gen做并发收集.
在Hotspot JVM实现的Serial GC, Parallel GC, CMS, G1 GC中大致可以对应到某个Young GC和Old GC算法组合; 。
很多人都见过JVM调优建议里使用这个参数,对吧?但是为什么要用它,什么时候应该用而什么时候用了会掉坑里呢?
首先,要了解的是这个参数的作用。在Oracle/Sun JDK这个具体实现上,System.gc()的默认效果是引发一次stop-the-world的Full GC,由上面所知就是针对于整个GC堆做内存垃圾收集.
再次,如果采用了用了-XX:+DisableExplicitGC参数后,System.gc()的调用就会变成一个空调用,完全不会触发任何GC(但是“函数调用”本身的开销还是存在的哦~).
java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:633)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:98)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
import java.nio.*;
public class DisableExplicitGCDemo {
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
ByteBuffer.allocateDirect(128);
}
System.out.println("Done");
}
}
然后编译、运行.
$ java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)
$ javac DisableExplicitGCDemo.java
$ java -XX:MaxDirectMemorySize=10m -XX:+PrintGC -XX:+DisableExplicitGC DisableExplicitGCDemo
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
at java.nio.Bits.reserveMemory(Bits.java:633)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:98)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
at DisableExplicitGCDemo.main(DisableExplicitGCDemo.java:6)
$ java -XX:MaxDirectMemorySize=10m -XX:+PrintGC DisableExplicitGCDemo
[GC 10996K->10480K(120704K), 0.0433980 secs]
[Full GC 10480K->10415K(120704K), 0.0359420 secs]
Done
可以看到,同样的程序,不带 -XX:+DisableExplicitGC 时能正常完成运行,而带上这个参数后却出现了OOM。-XX:MaxDirectMemorySize=10m限制了DirectByteBuffer能分配的空间的限额,以便问题更容易展现出来。不用这个参数就得多跑一会儿了.
循环不断申请DirectByteBuffer但并没有引用,所以这些DirectByteBuffer应该刚创建出来就已经满足被GC的条件,等下次GC运行的时候就应该可以被回收.
实际上却没这么简单。DirectByteBuffer是种典型的“冰山”对象,也就是说它的Java对象虽然很小很无辜,但它背后却会关联着一定量的native memory资源,而这些资源并不在GC的控制之下,需要自己注意控制好.
对JVM如何使用native memory不熟悉的同学可以研究一下这篇演讲,“Where Does All the Native Memory Go”.
Oracle/Sun JDK的实现里,DirectByteBuffer有几处值得注意的地方.
"A cleaner tracks a referent object and encapsulates a thunk of arbitrary cleanup code. Some time after the GC detects that a cleaner's referent has become phantom-reachable, the reference-handler thread will run the cleaner." 。
/**
* General-purpose phantom-reference-based cleaners.
*
* <p> Cleaners are a lightweight and more robust alternative to finalization.
* They are lightweight because they are not created by the VM and thus do not
* require a JNI upcall to be created, and because their cleanup code is
* invoked directly by the reference-handler thread rather than by the
* finalizer thread. They are more robust because they use phantom references,
* the weakest type of reference object, thereby avoiding the nasty ordering
* problems inherent to finalization.
*
* <p> A cleaner tracks a referent object and encapsulates a thunk of arbitrary
* cleanup code. Some time after the GC detects that a cleaner's referent has
* become phantom-reachable, the reference-handler thread will run the cleaner.
* Cleaners may also be invoked directly; they are thread safe and ensure that
* they run their thunks at most once.
*
* <p> Cleaners are not a replacement for finalization. They should be used
* only when the cleanup code is extremely simple and straightforward.
* Nontrivial cleaners are inadvisable since they risk blocking the
* reference-handler thread and delaying further cleanup and finalization.
*
*
* @author Mark Reinhold
* @version %I%, %E%
*/
Oracle/Sun JDK中的HotSpot VM只会在Old Gen GC(Full GC/Major GC或者Concurrent GC都算)的时候才会对Old Gen中的对象做Reference Processing,而在Young GC/Minor GC时只会对Young Gen里的对象做Reference processing。Full GC会对Old Gen做Reference processing,进而能触发Cleaner对已死的DirectByteBuffer对象做清理工作.
如果很长一段时间里没做过GC或者只做了Young GC的话则不会在Old Gen触发Cleaner的工作,那么就可能让本来已经死了的、但已经晋升到Old Gen的DirectByteBuffer关联的Native Memory得不到及时释放 .
为DirectByteBuffer分配空间过程中会显式调用System.gc(),以通过Full GC来强迫已经无用的DirectByteBuffer对象释放掉它们关联的native memory .
// These methods should be called whenever direct memory is allocated or
// freed. They allow the user to control the amount of direct memory
// which a process may access. All sizes are specified in bytes.
static void reserveMemory(long size) {
synchronized (Bits.class) {
if (!memoryLimitSet && VM.isBooted()) {
maxMemory = VM.maxDirectMemory();
memoryLimitSet = true;
}
if (size <= maxMemory - reservedMemory) {
reservedMemory += size;
return;
}
}
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException x) {
// Restore interrupt status
Thread.currentThread().interrupt();
}
synchronized (Bits.class) {
if (reservedMemory + size > maxMemory)
throw new OutOfMemoryError("Direct buffer memory");
reservedMemory += size;
}
}
这几个实现特征使得Oracle/Sun JDK依赖于System.gc()触发GC来保证DirectByteMemory的清理工作能及时完成.
如果打开了-XX:+DisableExplicitGC,清理工作就可能得不到及时完成,于是就有机会见到direct memory的OOM,也就是上面的例子演示的情况。我们这边在实际生产环境中确实遇到过这样的问题.
如果你在使用Oracle/Sun JDK,应用里有任何地方用了direct memory,那么使用-XX:+DisableExplicitGC要小心。如果用了该参数而且遇到direct memory的OOM,可以尝试去掉该参数看是否能避开这种OOM。如果担心System.gc()调用造成Full GC频繁,可以尝试下面提到 -XX:+ExplicitGCInvokesConcurrent 参数 。
最后此篇关于深度剖析|【JVM深层系列】[HotSpotVM研究系列]JVM调优的"标准参数"的各种陷阱和坑点分析(攻克盲点及混淆点)「1」的文章就讲到这里了,如果你想了解更多关于深度剖析|【JVM深层系列】[HotSpotVM研究系列]JVM调优的"标准参数"的各种陷阱和坑点分析(攻克盲点及混淆点)「1」的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
简而言之:我想从可变参数模板参数中提取各种选项,但不仅通过标签而且通过那些参数的索引,这些参数是未知的 标签。我喜欢 boost 中的方法(例如 heap 或 lockfree 策略),但想让它与 S
我可以对单元格中的 excel IF 语句提供一些帮助吗? 它在做什么? 对“BaselineAmount”进行了哪些评估? =IF(BaselineAmount, (Variance/Baselin
我正在使用以下方法: public async Task Save(Foo foo,out int param) { ....... MySqlParameter prmparamID
我正在使用 CodeGear RAD Studio IDE。 为了使用命令行参数测试我的应用程序,我多次使用了“运行 -> 参数”菜单中的“参数”字段。 但是每次我给它提供一个新值时,它都无法从“下拉
我已经为信用卡类编写了一些代码,粘贴在下面。我有一个接受上述变量的构造函数,并且正在研究一些方法将这些变量格式化为字符串,以便最终输出将类似于 号码:1234 5678 9012 3456 截止日期:
MySql IN 参数 - 在存储过程中使用时,VarChar IN 参数 val 是否需要单引号? 我已经像平常一样创建了经典 ASP 代码,但我没有更新该列。 我需要引用 VarChar 参数吗?
给出了下面的开始,但似乎不知道如何完成它。本质上,如果我调用 myTest([one, Two, Three], 2); 它应该返回元素 third。必须使用for循环来找到我的解决方案。 funct
将 1113355579999 作为参数传递时,该值在函数内部变为 959050335。 调用(main.c): printf("%d\n", FindCommonDigit(111335557999
这个问题在这里已经有了答案: Is Java "pass-by-reference" or "pass-by-value"? (92 个回答) 关闭9年前。 public class StackOve
我真的很困惑,当像 1 == scanf("%lg", &entry) 交换为 scanf("%lg", &entry) == 1 没有区别。我的实验书上说的是前者,而我觉得后者是可以理解的。 1 =
我正在尝试使用调用 SetupDiGetDeviceRegistryProperty 的函数使用德尔福 7。该调用来自示例函数 SetupEnumAvailableComPorts .它看起来像这样:
我需要在现有项目上实现一些事件的显示。我无法更改数据库结构。 在我的 Controller 中,我(从 ajax 请求)传递了一个时间戳,并且我需要显示之前的 8 个事件。因此,如果时间戳是(转换后)
rails 新手。按照多态关联的教程,我遇到了这个以在create 和destroy 中设置@client。 @client = Client.find(params[:client_id] || p
通过将 VM 参数设置为 -Xmx1024m,我能够通过 Eclipse 运行 Java 程序-Xms256M。现在我想通过 Windows 中的 .bat 文件运行相同的 Java 程序 (jar)
我有一个 Delphi DLL,它在被 Delphi 应用程序调用时工作并导出声明为的方法: Procedure ProduceOutput(request,inputs:widestring; va
浏览完文档和示例后,我还没有弄清楚 schema.yaml 文件中的参数到底用在哪里。 在此处使用 AWS 代码示例:https://github.com/aws-samples/aws-proton
程序参数: procedure get_user_profile ( i_attuid in ras_user.attuid%type, i_data_group in data_g
我有一个字符串作为参数传递给我的存储过程。 dim AgentString as String = " 'test1', 'test2', 'test3' " 我想在 IN 中使用该参数声明。 AND
这个问题已经有答案了: When should I use "this" in a class? (17 个回答) 已关闭 6 年前。 我运行了一些java代码,我看到了一些我不太明白的东西。为什么下
我输入 scroll(0,10,200,10);但是当它运行时,它会传递字符串“xxpos”或“yypos”,我确实在没有撇号的情况下尝试过,但它就是行不通。 scroll = function(xp
我是一名优秀的程序员,十分优秀!