java安全点_关于OopMap、SafePoint(安全点)以及安全区域

1.OopMap

之前我们提到,在正式的GC之前总是需要进行可达性分析来查找内存中所有存活的对象,以便GC能够正确的回收已经死亡的对象。那么对于一个十分复杂的系统,每次GC的时候都要遍历所有的引用肯定是不现实的。因为在可达性分析的时候,需要进行Stop The World,程序中的线程需要停止来配合可达性分析。就好像是你女朋友在打扫卫生的时候(什么,你还没有女朋友?这还能难道程序员了?new 一个啊!),肯定不会让你走来走去的。所以,你肯定在内心里也希望你女朋友打扫卫生快一点,因为你的膀胱已经快要爆炸了。对于程序来说有也一样,也希望GC的时候快一点,以便让程序高效地完成工作。

所以,每次直接遍历整个引用链肯定是不现实的。 为了应对这种尴尬的问题,最早有保守式GC和后来的准确式GC。这里准确式GC就会提到一个OopMap,用来保存类型的映射表。

保守式GC

在进行GC的时候,会从一些已知的位置(GC Roots)开始扫描内存,扫描到一个数字就判断他是不是可能是指向GC堆中的一个指针(这里会涉及上下边界检查(GC堆的上下界是已知的)、对齐检查(通常分配空间的时候会有对齐要求,假如说是4字节对齐,那么不能被4整除的数字就肯定不是指针),之类的。)。然后一直递归的扫描下去,最后完成可达性分析。这种模糊的判断方法因为无法准确判断一个位置上是否是真的指向GC堆中的指针,所以被命名为保守式GC。这种可达性分析的方式因为不需要准确的判断出一个指针,所以效率快,但是也正因为这种特点,他存在下面两个明显的缺点:

因为是模糊的检查,所以对于一些已经死掉的对象,很可能会被误认为仍有地方引用他们,GC也就自然不会回收他们,从而引起了无用的内存占用,就是典型的占着茅坑不拉屎,造成资源浪费。

由于不知道疑似指针是否真的是指针,所以它们的值都不能改写;移动对象就意味着要修正指针。换言之,对象就不可移动了。有一种办法可以在使用保守式GC的同时支持对象的移动,那就是增加一个间接层,不直接通过指针来实现引用,而是添加一层“句柄”(handle)在中间,所有引用先指到一个句柄表里,再从句柄表找到实际对象。这样,要移动对象的话,只要修改句柄表里的内容即可。但是这样的话引用的访问速度就降低了。Sun JDK的Classic VM用过这种全handle的设计,但效果实在算不上好。

2.准确式GC

与保守式GC相对的就是准确式GC,何为准确式GC?就是我们准确的知道,某个位置上面是否是指针,对于java来说,就是知道对于某个位置上的数据是什么类型的,这样就可以判断出所有的位置上的数据是不是指向GC堆的引用,包括栈和寄存器里的数据。

网上看了下说是实现这种要求的方法有好几种,但是在java中实现的方式是:从我外部记录下类型信息,存成映射表,在HotSpot中把这种映射表称之为OopMap,不同的虚拟机名称可能不一样。

实现这种功能,需要虚拟机的解释器和JIT编译器支持,由他们来生成OopMap。生成这样的映射表一般有两种方式:

每次都遍历原始的映射表,循环的一个个偏移量扫描过去;这种用法也叫“解释式”;

为每个映射表生成一块定制的扫描代码(想像扫描映射表的循环被展开的样子),以后每次要用映射表就直接执行生成的扫描代码;这种用法也叫“编译式”。

总而言之,GC开始的时候,就通过OopMap这样的一个映射表知道,在对象内的什么偏移量上是什么类型的数据,而且特定的位置记录下栈和寄存器中哪些位置是引用。

2.SafePoint(安全点)

上面讲到了为了快点进行可达性的分析,使用了一个引用类型的映射表,可以快速的知道对象内或者栈和寄存器中哪些位置是引用了。

但是随着而来的又有一个问题,就是在方法执行的过程中, 可能会导致引用关系发生变化,那么保存的OopMap就要随着变化。如果每次引用关系发生了变化都要去修改OopMap的话,这又是一件成本很高的事情。所以这里就引入了安全点的概念。

什么是安全点?OopMap的作用是为了在GC的时候,快速进行可达性分析,所以OopMap并不需要一发生改变就去更新这个映射表。只要这个更新在GC发生之前就可以了。所以OopMap只需要在预先选定的一些位置上记录变化的OopMap就行了。这些特定的点就是SafePoint(安全点)。由此也可以知道,程序并不是在所有的位置上都可以进行GC的,只有在达到这样的安全点才能暂停下来进行GC。

既然安全点决定了GC的时机,那么安全点的选择就至为重要了。安全点太少,会让GC等待的时间太长,太多会浪费性能。所以安全点的选择是以程序“是否具有让程序长时间执行的特征”为标准的(这句话是从书上看来的,不知道作者自己能不能看明白这话啥意思,反正我是看不懂),所以我们这里了解一下结果就行了。一般会在如下几个位置选择安全点:

循环的末尾

方法临返回前 / 调用方法的call指令后

可能抛异常的位置

还有一个需要考虑的问题就是,如何让程序在要进行GC的时候都跑到最近的安全点上停顿下来。这里有两种方案:

抢断式中断

抢断式中断就是在GC的时候,让所有的线程都中断,如果这些线程中发现中断地方不在安全点上的,就恢复线程,让他们重新跑起来,直到跑到安全点上。(现在几乎没有虚拟机采用这种方式,原因不详)

主动式中断

主动式中断在GC的时候,不会主动去中断线程,仅仅是设置一个标志,当程序运行到安全点时就去轮训该位置,发现该位置被设置为真时就自己中断挂起。所以轮训标志的地方是和安全点重合的,另外创建对象需要分配内存的地方也需要轮询该位置。

3.安全区域

安全点的使用似乎解决了OopMap计算的效率的问题,但是这里还有一个问题。安全点需要程序自己跑过去,那么对于那些已经停在路边休息或者看风景的程序(比如那些处在Sleep或者Blocked状态的线程),他们可能并不会在很短的时间内跑到安全点去。所以这里为了解决这个问题,又引入了安全区域的概念。

安全区域很好理解,就是在程序的一段代码片段中并不会导致引用关系发生变化,也就不用去更新OopMap表了,那么在这段代码区域内任何地方进行GC都是没有问题的。这段区域就称之为安全区域。线程执行的过程中,如果进入到安全区域内,就会标志自己已经进行到安全区域了。那么虚拟机要进行GC的时候,发现该线程已经运行到安全区域,就不会管该线程的死活了。所以,该线程在脱离安全区域的时候,要自己检查系统是否已经完成了GC或者根节点枚举(这个跟GC的算法有关系),如果完成了就继续执行,如果未完成,它就必须等待收到可以安全离开安全区域的Safe Region的信号为止。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336482.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javaslang_使用Javaslang的Java 8中的功能数据结构

javaslangJava 8的lambda(λ)使我们能够创建出色的API。 它们极大地提高了语言的表达能力。 Javaslang利用lambda来基于功能模式创建各种新功能。 其中之一是功能性集合库,旨在替代Java的标准集合。 (这只是鸟瞰图,您…

LeetCode 面试题 链表中倒数第K个点

解题思路,倒数第K个点,位于正数N-K1的位置。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* getKthFromEn…

java调用kafka接口发送数据_Java调用Kafka生产者,消费者Api及相关配置说明

本次的记录内容包括:1.Java调用生产者APi流程2.Kafka生产者Api的使用及说明3.Kafka消费者Api的使用及说明4.Kafka消费者自动提交Offset和手动提交Offset5.自定义生产者的拦截器,分区器那么接下来我就带大家熟悉以上Kafka的知识说明1.Java调用生产者APi流…

java中的方法求和_在Java中模拟求和类型的巧妙解决方法

java中的方法求和在继续阅读实际文章之前&#xff0c;我想感谢令人敬畏的Javaslang库的作者Daniel Dietrich &#xff0c;他在我面前有了这个主意&#xff1a; lukaseder尝试使用静态方法<T&#xff0c;T1扩展T&#xff0c;... Tn扩展T> Seq <T> toSeq&#xff08…

java如何模拟请求_单元测试如何模拟用户请求

python web自动化测试设计构工具书40.9元包邮(需用券)去购买 >错误正当我高高兴兴写完后台c层的测试代码准备提交时&#xff0c;测试机器人报了很多401错误&#xff0c;把代码拉下来一看&#xff0c;原来当我写代码时&#xff0c;我的伙伴已经写好后台的拦截器了&#xff0c…

LeetCode 237. 删除链表中的节点

原题链接 解题思路&#xff1a;后面的的结点内容覆盖前面的结点内容 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:void deleteNode(ListN…

java异步接口转同步接口_如果今天设计了Java:同步接口

java异步接口转同步接口Java已经走了很长一段路。 很长的路要走。 它带有早期设计决策中的所有“垃圾”。 一遍又一遍后悔的一件事是&#xff0c; 每个对象&#xff08;可能&#xff09;都包含一个监视器 。 几乎没有必要这样做&#xff0c;并且最终在Java 5中纠正了该缺陷&am…

LeetCode 83. 删除排序链表中的重复元素

原题链接 解法&#xff1a;通过一个指针从头到尾进行扫描 class Solution { public:ListNode* deleteDuplicates(ListNode* head) {if(!head)return nullptr;auto p1 head;while(p1->next){if(p1->next->val p1->val)p1->nextp1->next->next;else p1 …

java 使按钮被选中_java – 让我的单选按钮在Android中被选中

当我运行时,可以单击对话框,我的单选按钮不会像预期的那样被选中package edu.elon.cs.mobile;public class PTCalculator extends Activity{private RadioButton maleRadioButton;private RadioButton femaleRadioButton;private EditText ageEdit;private EditText pushUpsEdi…

后端 java ee_刷新器-Java EE 7后端十大功能

后端 java ee这是我的小型Java EE 7复习系列的第二部分。 在进行了简要概述的第一篇介绍之后&#xff0c;我决定请Arjan Tijms撰写有关Java EE 7中他最喜欢的后端新功能的信息。如果您关注Java EE领域&#xff0c;您将会知道Arjan。 他是Java EE开发人员&#xff0c;JSF和Secur…

java enum 报错_enum报错问题,求大神帮看下

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼public enum OrderStatusEnum {NOT_PAY("未付款", 0),NOT_YET_SHIPPEND("待发货", 1),YET_SHIPPEND("已发货", 2),HAS_BEEN_COMPLETED("已完成", 3),HAS_BEEN_CANANCELLED("已取消&q…

LeetCode 160 相交链表

原题链接 解题思路1&#xff1a;哈希表 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode *getIntersectionNode(ListNode *headA, L…

java cucumber_为Java + STANDARD值引入Cucumber

java cucumber作为软件开发人员&#xff0c;我们都有最喜欢的工具来使我们成功。 许多人在开始工作时就很适合这份工作&#xff0c;但很快就不见了。 其他人则需要太多的设置和培训才能“将脚趾浸入水中”&#xff0c;只是为了简单地确定它们是否是正确的工具即可。 Cucumber …

LeetCode 234 回文链表

原题链接 解题思路&#xff1a;使用vector来存储链表&#xff0c;然后来检查其中每一个元素&#xff0c;是否组成回文 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/…

文章id 文章标题点击量php,WordPress如何通过文章ID获取文章标题等信息

如果我们想要在某一个主题的php文件中调用文章的标题&#xff0c;内容等信息&#xff0c;而在WordPress中唯一一直不会改变的就是文章发布时生成的ID&#xff0c;我们只需要获取文章的ID&#xff0c;即可通过文章ID来获取我们想要的文章信息。调用方法php$id // 文章的 id$tit…

javafx 表格列拖拉_JavaFX技巧22:“自动调整大小(树)”表列

javafx 表格列拖拉JavaFX “缺少功能调查”中提到的“缺少功能”的第一件事就是能够自动调整表/树表中的列大小。 没错&#xff0c;没有公共API是正确的&#xff0c;但是当您密切关注时&#xff0c;您会注意到JavaFX内部一定有执行此操作的代码&#xff0c;因为用户可以通过双击…

LeetCode 1290 二进制链表转整数

原题链接 解题思路&#xff0c;二进制转十进制模拟法 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:int getDecimalValue(ListNode* head)…

java 实例对象拷贝,实例详解java对象拷贝

这篇文章主要介绍了java对象拷贝详解及实例的相关资料,需要的朋友可以参考下java对象拷贝详解及实例Java赋值是复制对象引用&#xff0c;如果我们想要得到一个对象的副本&#xff0c;使用赋值操作是无法达到目的的&#xff1a;Testpublic void testassign(){Person p1new Perso…

LeetCode 344 反转字符串

原题链接 解题思路&#xff1a;双指针首位交换&#xff0c;两个指针重合遍历交换完成 class Solution { public:void reverseString(vector<char>& s) {if(s.empty())return;int left0;int rights.size()-1;while(left<right){swap(s[left],s[right]);left;righ…

javaone_JavaOne 2015:高级模块化开发

javaoneJavaOne 2015看到了Project Jigsaw团队关于Java 9中的模块化的一系列讨论 。它们都是非常有趣的&#xff0c;并且充满了宝贵的信息&#xff0c;我敦促每个Java开发人员都注意它们。 除此之外&#xff0c;我想给社区一种搜索和引用它们的方法&#xff0c;因此我在这里总…