JVM05_堆的概述、内存结构、复制算法、Minor|Major|Full GC、私有区域TLAB、对象分配、参数总结、逃逸分析、栈上分配、锁消除、标量替换(三)

简介: ⑨. 堆空间参数总结⑩. 逃逸分析

⑨. 堆空间参数总结


①. -XX:+PrintFlagsInitial : 查看所有的参数的默认初始值


②. -XX:+PrintFlagsFinal : 查看所有的参数的最终值(可能会存在修改(:表示修改了),不再是初始值)


③. 具体查看某个参数的指令:


(jps:查看当前运行中的进程


jinfo -flag SurvivorRatio 进程id)


④. -Xms:初始堆空间内存 (默认为物理内存的1/64)


⑤. -Xmx:最大堆空间内存(默认为物理内存的1/4)


⑥. -Xmn:设置新生代的大小。(初始值及最大值)


⑦. -XX:NewRatio:配置新生代与老年代在堆结构的占比


(默认:-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整个堆的1/3


可以修改-XX:NewRatio=4,表示新生代占1,老年代占4,新生代占整个堆的1/5)


微信图片_20220106140744.png


⑧. -XX:SurvivorRatio:设置新生代中Eden和S0/S1空间的比例


(Eden空间和另外两个Survivor空间缺省所占的比例是8:1:1)


⑨. -XX:MaxTenuringThreshold:设置新生代垃圾的最大年龄


⑩. -XX:+PrintGCDetails:输出详细的GC处理日志


(如下这两种方式是简单的打印


打印gc简要信息:① -XX:+PrintGC ② -verbose:gc)


⑩①. -XX:HandlePromotionFailure:是否设置空间分配担保


(JDK6之后,只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进

行Minor GC,否则将进行Full GC)


内存分配策略(或对象提升(Promotion)规则)


(1). 在繁盛Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象的总空间


====如果大于,则此次Minor GC是安全的


====如果小于,则虚拟机会检查查看-XX:HandlePromotionFailure设置值是否允许担保失败


=====如果 HandlePromotionFailure=true,那么会继续检查老年代最大可用连续空间是否大于历次晋级到老年代的对象的平均大小


========如果大于,则尝试进行一次Minor GC,但是这次Minor GC依然是有风险的


========如果小于,则改为一次Full GC


=====如果HandlePromotionFailure=false,则改为进行一次Full GC


(2). 在JDK6 Update24之后,HandlePromotionFailure参数不会再影响虚拟机的空间分配担保策略,观察OpenJDK中源码变化,虽然源码中还定义了HandlePromotionFailure参数,但是在代码中已经不会再使用它


(3). JDK6 Update24之后规则变为只有老年代的连续空间大于新生代对象总大小或者历次晋身的平均大小就会进行Minor GC,否则将进行Full GC


⑩. 逃逸分析


  • ①. 如何将堆上的对象分配到栈,需要使用逃逸分析手段


  1. 当一个对象在方法中被定义后,对象只在方法内部使用(这里关注的是这个对象的实体),则认为没有发生逃逸。


  1. 当一个对象在方法中被定义后,它被外部方法所引用,则认为发生逃逸。例如作为调用参数传递到其他地方中


  • ②. 代码演示


//(1). 没有发生逃逸的对象,则可以分配到栈上,随着方法执行的结束,栈空间就被移除
public void my_method() {
    V v = new V();
    // use v
    // ....
    v = null;
}
//(2). 下面代码中的 StringBuffer sb 发生了逃逸
public static StringBuffer createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb;
}
//如果想要StringBuffer sb不发生逃逸,可以这样写
public static String createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}

③. 逃逸分析的举例


/**
 * 逃逸分析
 *
 * 如何快速的判断是否发生了逃逸分析,大家就看new的对象实体是否有可能在方法外被调用。
 */
public class EscapeAnalysis {
    public EscapeAnalysis obj;
    /*
    方法返回EscapeAnalysis对象,发生逃逸
     */
    public EscapeAnalysis getInstance(){
        return obj == null? new EscapeAnalysis() : obj;
    }
    /*
    为成员属性赋值,发生逃逸
     */
    public void setObj(){
        this.obj = new EscapeAnalysis();
    }
    //思考:如果当前的obj引用声明为static的? 仍然会发生逃逸。
    /*
    对象的作用域仅在当前方法中有效,没有发生逃逸
     */
    public void useEscapeAnalysis(){
        EscapeAnalysis e = new EscapeAnalysis();
    }
    /*
    引用成员变量的值,发生逃逸
     */
    public void useEscapeAnalysis1(){
        EscapeAnalysis e = getInstance(); //这个e对象,本身就是从外面的方法逃逸进来的
        //getInstance().xxx()同样会发生逃逸
    }
}


④. 在JDK1.7版本之后,HotSpot中默认就已经开启了逃逸分析


如果使用的是较早的版本,开发人员则可以通过:


选项“-XX:+DoEscapeAnalysis"显式开启逃逸分析


通过选项“-XX:+PrintEscapeAnalysis"查看逃逸分析的筛选结果


  • 结论: ⑤. 开发中能使用局部变量的,就不要使用在方法外定义


  • ⑥. 使用逃逸分析,编译器可以对代码做如下优化:


栈上分配:将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会发生逃逸,对象可能是栈上分配的候选,而不是堆上分配


同步省略:如果一个对象被发现只有一个线程被访问到,那么对于这个对象的操作可以不考虑同步。


分离对象或标量替换:有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中


相关文章
|
5月前
|
存储 监控 算法
基于 Go 语言跳表结构的局域网控制桌面软件进程管理算法研究
针对企业局域网控制桌面软件对海量进程实时监控的需求,本文提出基于跳表的高效管理方案。通过多级索引实现O(log n)的查询、插入与删除性能,结合Go语言实现并发安全的跳表结构,显著提升进程状态处理效率,适用于千级进程的毫秒级响应场景。
237 15
|
5月前
|
分布式计算 并行计算 算法
《数据之美》:图结构的精妙世界与算法实践
图是表示多对多关系的非线性数据结构,由顶点和边组成,可建模社交网络、路径导航等复杂系统。核心算法包括BFS/DFS遍历、Dijkstra最短路径、Floyd-Warshall全源最短路径,以及Prim和Kruskal最小生成树算法,广泛应用于推荐系统、社交分析与路径规划。
|
6月前
|
运维 监控 JavaScript
基于 Node.js 图结构的局域网设备拓扑分析算法在局域网内监控软件中的应用研究
本文探讨图结构在局域网监控系统中的应用,通过Node.js实现设备拓扑建模、路径分析与故障定位,提升网络可视化、可追溯性与运维效率,结合模拟实验验证其高效性与准确性。
373 3
|
6月前
|
存储 监控 算法
企业电脑监控系统中基于 Go 语言的跳表结构设备数据索引算法研究
本文介绍基于Go语言的跳表算法在企业电脑监控系统中的应用,通过多层索引结构将数据查询、插入、删除操作优化至O(log n),显著提升海量设备数据管理效率,解决传统链表查询延迟问题,实现高效设备状态定位与异常筛选。
179 3
|
Java 编译器 Go
go的内存逃逸分析
内存逃逸分析是Go编译器在编译期间根据变量的类型和作用域,确定变量分配在堆上还是栈上的过程。如果变量需要分配在堆上,则称作内存逃逸。Go语言有自动内存管理(GC),开发者无需手动释放内存,但编译器需准确分配内存以优化性能。常见的内存逃逸场景包括返回局部变量的指针、使用`interface{}`动态类型、栈空间不足和闭包等。内存逃逸会影响性能,因为操作堆比栈慢,且增加GC压力。合理使用内存逃逸分析工具(如`-gcflags=-m`)有助于编写高效代码。
248 2
|
存储 IDE Java
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
737 4
|
算法 Java
堆内存分配策略解密
本文深入探讨了Java虚拟机中堆内存的分配策略,包括新生代(Eden区和Survivor区)与老年代的分配机制。新生代对象优先分配在Eden区,当空间不足时执行Minor GC并将存活对象移至Survivor区;老年代则用于存放长期存活或大对象,避免频繁内存拷贝。通过动态对象年龄判定优化晋升策略,并介绍Full GC触发条件。理解这些策略有助于提高程序性能和稳定性。
|
8月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
2742 0
|
8月前
|
存储 缓存 NoSQL
内存管理基础:数据结构的存储方式
数据结构在内存中的存储方式主要包括连续存储、链式存储、索引存储和散列存储。连续存储如数组,数据元素按顺序连续存放,访问速度快但扩展性差;链式存储如链表,通过指针连接分散的节点,便于插入删除但访问效率低;索引存储通过索引表提高查找效率,常用于数据库系统;散列存储如哈希表,通过哈希函数实现快速存取,但需处理冲突。不同场景下应根据访问模式、数据规模和操作频率选择合适的存储结构,甚至结合多种方式以达到最优性能。掌握这些存储机制是构建高效程序和理解高级数据结构的基础。
880 1