java 线程栈大小配置,jvm之栈、堆,jvm默认栈空间大小-程序员宅基地

技术标签: java 线程栈大小配置  

jvm之栈、堆,jvm默认栈空间大小

1. Java Virtual Machine

​人群当中,一位叫java的小伙子正向周围一众人群细数着自己取得的荣耀与辉煌。就在此时,c老头和c++老头缓步走来,看着被众人围住的java,c老头感叹地对着身旁的c++说道:“原以为你就可以挑起我的梁子一直走下去的。”

​c++笑着回应道:“江山代有才人出,这世界以后总会是90后甚至00后的天下!”

察觉到c和c++的java连忙走出人群,说道:“两位前辈谦虚了,这世界可还离不开两位前辈,我只不过是站在了两位前辈的肩上罢了。”

​“你这小子可是解决了我们不少的问题啊,像指针、多继承、内存管理......那时,可是有很多程序员对我们抱怨颇深!”c++夸赞道。

​“还有Java Virtual Machine,真的是一个不错的想法!”一旁的c补充道。

......

Java虚拟机,一直都是都是我们在学习Java的过程中反复提及的一个东西,那么JVM具体是怎样的呢?请看下图:

79d13df8f7957c6ecd3a29c9729eb632.png

​简单说来,JVM的工作就是通过类加载系统将字节码文件加载到内存当中去,加载到内存当中的数据,就从逻辑上形成了我们看到的图中的运行时数据区(内存模型),

随后执行引擎操作/调度内存模型中数据执行程序。

​现在看到内存模型里面的东西,大家是否有些眼熟呢?现在回想起自己面试时,遇到的JVM面试题是不是全是关于内存模型里面的东西。比如:栈、堆、Eden、Survivor、GC等等。

2. 举个小栗子

public class Example{

public int add(){

int a = 3;

int b = 4;

int c = a + b;

return c;

}

public static void main(String[] args){

Example e1 = new Example();

e1.add();

//.......

}

//......

}

​这个栗子是在干啥,不用多说吧!今天我们就要来慢慢地剥开它,以往剥开吃得太快就没有什么感觉了。

3. 栈

​栈,全称为Java 虚拟机栈,线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

​怎样解释上面的话呢?那就需要开始剥栗子了!刀来(大喝一声)!

​当栗子开始执行时,由于只有一个main线程,因而JVM只需要为main线程分配好栈区的内存(话句话说如果有多个线程,自然就会有多个栈区,并且为各自线程私有)。OK! main继续执行,就会遇到main()方法,遇到之后呢!JVM又会在栈区当中再划出一个小块来存放main()方法执行过程的数据,这一小块区域也就是栈帧。main()方法执行过程中又有一个add()方法出现了,同样地,JVM又会再为add()分配一个栈帧,同时压入到栈区,以后再遇到其他方法也是如此。当然,方法在执行完成之后,便会弹出并释放内存,当线程中栈区的所有方法都返回之后,程序也就算是执行完毕了。

​那么栈帧又是何许物业?咦,我刀呢?算了,手撕吧。

​当我们扯开栈区,撕开栈帧,一不小心,局部变量表、操作数栈、动态链接、方法出口......哗啦啦地散落一地。

1e2d7d7a7b1e3bf7f0491bbc1efda535.png

​捡起add()栈帧的局部变量表和操作数栈就可以看到这样一个画面,在执行栗子中add()方法中的三行代码时,局部变量表和操作数栈的一个变化过程:首先,执行int a = 3;局部变量表中会分配出一个int区域,表示为a;同时iconst命令使得操作数栈中压入了常量3,然后再由istore命令将3弹出,赋值给局部变量表中a。同样,int b = 4; 这一行代码也是如此。然后,int c = a + b;从右往左开始,先执行a + b,也就是iload命令从局部变量中取出a、b对应的值,再将iadd后的值push进操作数栈中,剩下的便是int c = 7的操作了。

​通过上面的栗子,就很容易明白;局部变量表,顾名思义就是存放每个方法中的局部变量(即编译器可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址))所在处,如图中的a、b。操作数栈,也就是存放的就是方法当中的各种操作数的临时空间,又如栗子中的3、4。

​动态链接:Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以指向常量池的引用作为参数,而将部分符号引用在运行期间转化为直接引用,这种转化即为动态链接。这个解释当中会涉及到许多概念,比如常量池、符号引用等,要想理解这些概念,就需要去了解class文件的结构,内容太多就不在这里详细描述了。

​方法出口:简单来说,就是用于标记当前方法执行完成之后,应该返回到下一条指令执行位置。比如就上面的栗子而言,add()在执行完毕之后,就应该返回到e1.add()之后继续执行main()后面的代码。

4. 堆

​对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是用于存放对象实例和数组。除此之外,堆区还涉及到JVM中一个非常重要的工作--GC(Garbage Collection)。

0b519cbacb39f455881feeba68b3f685.png

​从图中就可以看出栈和堆之间的关系,对于new的对象,栈中局部变量表只会存放在堆中的地址引用,具体实例变量的空间分配都在堆中。

​而堆中的内存区域又会划分为年轻代和老年代两部分,其中一般情况下年轻代占1/3内存,老年代占2/3内存;年轻代又被划分为Eden区(伊甸园区)和两个Survivor区(幸存区),各自分别占年轻代空间的8/10、/1/10、1/10。也就是说如果堆内存区域有600M,那么年轻代200M、老年代400M、Eden区160M、S0区20M、S1区20M。

​这样划分区域的目的是什么呢?这个回答就关系到JVM的GC机制了。

​首先,程序一开始,所有的实例对象都会生成在Eden区中,当Eden区满了的时候,这时就会触发minor gc,jvm使用gc roots的查找方式将非垃圾对象移动(复制算法)到S0区域中去,并且将Eden区中的其他对象视为垃圾对象,清空Eden区。

​当实例对象再次充满Eden区时,又会触发minor gc;但是这次是将Eden区和S0区中的所有非垃圾对象移动到S1中,并清空Eden区和S0区;同样下次minor gc时,就是将Eden区和S1区中的非垃圾对象转移到S0中......当然,这个左手倒右手过程并不是无休止的。在反复minor gc的过程中,每个对象身上还有一个叫做分代年龄的属性,每次minor gc对象的分代年龄就会加1,当达到15(默认情况)时,这个对象就会被放到老年代中去,成为长期存在的对象。除此之外,还有一种情况,即是当从Eden区复制内容到Survivor区时,复制内容大小超过S0或S1任一区域一半大小,也会直接被放入到老年代中,所以老年代才会需要那么大的区域,不然怎么抗得住这些年轻人这样搞~~。

​虽然老年代空间很大,但总会有满了的时候,这时麻烦的事情就出现了——full gc。在full gc时,jvm会先触发STW(Stop-The-World),也就是暂停其他所有的java进程,回收整个内存模型当中的内存资源,从而造成用户响应超时或者是系统无响应,这对于并发程序比较高的系统(比如秒杀活动)影响程度是极其之大的。

​通过gc机制,我们就可以得出一个简单有效的JVM优化办法,那就是减少full gc的次数,如何减少呢?只需要调整老年代和年轻代的内存空间分配使得在minor gc的过程中尽可能的消除大部分的垃圾对象。比如这种java -Xmx3072 -Xms3072M -Xmn2048M -Xss1M

​-Xmx3072M:设置JVM最大可用内存为3072M。

​-Xms3072M:设置JVM初始内存为3072M。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

​-Xmn2048M:设置年轻代大小为2G。增大年轻代后,将会减小年老代大小。不过此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

​-Xss1M:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。

​GC Roots:在上面的gc过程中,我们还提到了JVM是如何判断垃圾对象的。简单地来说,就是从gc roots的根出发(即局部变量表中的引用对象),一路沿着引用关系找,凡是能够被找到的对象都是非垃圾对象,并且会被移动到下一个它应该去的区域中。剩下的对象,会在区域清空时,一同被清理掉而无须关心。

5. 小结

​除了栈、堆之外,还有程序计数器、方法区(元空间)、本地方法栈,这些相对比较容易理解。

​程序计数器:用来记录当前指令执行完成后下一条指令的位置,由执行引擎来完成相应的修改操作。

​方法区(元空间):存放常量、静态变量、类信息等。

​本地方法栈:与java虚拟机栈类似,不过存放的是native方法执行时的局部变量等数据存放位置。因为native方法一般不是由java语言编写的,常见的就是.dll文件当中的方法(由C/C++编写),比如Thread类中start()方法在运行时就会调用到一个start0()方法,查看源码时就会看到private native void start0();这个方法就是一个本地方法。本地方法的作用就相当于是一个“接口”,用来连接java和其他语言的接口。

​另外,对于new出来的对象,无论是在栈的局部变量表还是在方法区中的空间中,存放的都只是对象在堆中的地址(引用),具体的空间分配是在堆中。

公众号:良许Linux

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

http://www.dengb.com/Linuxjc/1413206.htmlwww.dengb.comtruehttp://www.dengb.com/Linuxjc/1413206.htmlTechArticlejvm之栈、堆,jvm默认栈空间大小 1. Java Virtual Machine ​人群当中,一位叫java的小伙子正向周围一众人群细数着自己取得的荣耀与辉煌。就在...

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42344395/article/details/115146094

智能推荐

fractal 分形维数 盒子维 纹理特征_图像分形维数matlab-程序员宅基地

文章浏览阅读1.1w次,点赞4次,收藏30次。分形 盒子维纹理特征在纹理特征的提取中,纹理的分形维数特征(FD)是对纹理的一种重要描述。图像的纹理越复杂、细腻,则分形维数越大。提取分形维数特征的方法有很多种,理论以及计算的复杂度各有差异。本文中分形维数的计算方法采用的是 DBC(Differential Box-counting)即 差分盒子计数法。该方法是由Sarkar and Chaudhuri 于1994年前后提出的(An E_图像分形维数matlab

CEPH分布式集群搭建_ceph node name-程序员宅基地

文章浏览阅读346次。1 概述1.2 集群概述Ceph集群是一个集Monitors[1]、OSDs[2]、MDs[3]三种节点组成的一种集群。这里我所做的Ceph集群的搭建步骤主要以Monitor+OSDs为核心来搭建该集群,若掌握了这两个搭建集群的方法,理解其搭建流程,再在此基础上添加MDs就会变得很简单。总的来说,搭建集群难点在于集群前期的搭建以及让这个集群达到active(激活)状态,之后再添加OSD..._ceph node name

html 通过复选框获取当前行的数据_快速上手数据分析——让 Excel 成就你,而不是你迁就它...-程序员宅基地

文章浏览阅读335次。本篇文章主要讲解Excel的数据分析,想要系统学习Excel的朋友可以点击下方链接观看免费视频课程。https://edu.51cto.com/course/19145.html​edu.51cto.comhttps://edu.51cto.com/course/19156.html​edu.51cto.com新手学 Excel 2016 - 网易云课堂​study.163.com使用 Excel..._htm 如何获取表格中的当前行

POJ 2823单调队列 数组写法_单调队列写法-程序员宅基地

文章浏览阅读890次。Sliding WindowTime Limit: 12000MS Memory Limit: 65536KTotal Submissions: 46443 Accepted: 13422Case Time Limit: 5000MSDescriptionAn array of size n ≤ 106 is _单调队列写法

Android原生权限管理AppOps,安卓应用推荐:App Ops - 专治不给权限就不运行类软件...-程序员宅基地

文章浏览阅读812次。IT之家1月18日消息 相较于iOS软件,部分安卓应用在本来需求的权限之外还经常请求一些较为敏感的权限,例如通话、付费短信等,虽然部分软件也解释是为了增强用户使用的安全性和体验,但是对一部分喜欢保护个人隐私的用户来说还是有所疑虑。如果你也对一部分应用弹出的不相关权限请求不爽,现在治理它们有了新的方法,就是这款名为App Ops的软件,对于安卓7.0以上的系统该软件还支持后台运行,能够让应用在索要权...

keras、tensorflow与numpy版本对应问题_tensorflow和numpy对应关系-程序员宅基地

文章浏览阅读3.3w次,点赞3次,收藏51次。1、keras、tensorflow版本对应问题可以看这个:https://docs.floydhub.com/guides/environments/部分截图:2、numpy的版本问题像这样:FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecat就是numpy版本的..._tensorflow和numpy对应关系

随便推点

Python celery框架解决高并发问题并利用django发送邮件-程序员宅基地

文章浏览阅读2.2k次。第二十四章 Python celery框架解决高并发问题本节所讲内容: 24.1 celery的介绍 24.2 rabbitmq的安装 24.3 Celery结构分析和rabbitmq结合 24.4 实战:celery+Django实现异步发送邮件24.1 Celery介绍24.1.1 生产者消费者模式在学习Cel...

膜拜!Boss直聘一夜爆火,惨遭各一线大厂封杀的30W字Java面试总结究竟有多强?-程序员宅基地

文章浏览阅读402次。就在昨天在Boss直聘转发超90W次的一套面试题总结,已经被各家大厂封杀,究其原因竟然是太全面了,面试基本上百分之百必中!从而导致了市场的紊乱!但是楼主已经为大家扒了下来,整理成了PDF格式!本篇将会通过各个部分的面试题涵盖知识点脑图+面试题+答案的方式为大家展示!废话不多说我们直接进入正题,下面先为大家上一个总的目录大纲!前边那些基础的部分就不为大家展示了,没有太多的必要,我们直接从多线程与高并发、JVM开始聊起!需要资料的小伙伴,点赞加收藏,关注我之后添加小助理vx:bj.

python制作zzulioj排名动态图-程序员宅基地

文章浏览阅读2.8k次。日常爬取学校oj网站# -*- codeing = utf-8 -*-# @Time : 2021/3/11 22:45# @Author :老七疯狂吸氧# @file kozzulioj.py# @Software:PyCharmimport reimport requestsimport pandas as pdimport jsonimport timeimport numpy as nmimport tkinter as tkfrom pyecharts import op

如何 循环 字母 php,PHP-php循环打印a-z字母的疑惑-程序员宅基地

文章浏览阅读139次。读一下文档吧:docPHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z';...

arm Linux系统启动之----start_kernel函数_arm start函数-程序员宅基地

文章浏览阅读1k次。[cpp] view plaincopyhead-common.S ---具体做了哪些动作 ---跳转到init/main.c ---b start_kernel //关于start_kernel的强文深入理解linux内核,第八章 main.c asmlinkage void __init start_kernel(void)_arm start函数

hive使用beeline连接遇到的问题_beeline version 2.0.0 by apache hive beeline> !con-程序员宅基地

文章浏览阅读7.6k次,点赞2次,收藏14次。hiveserver2未启动如果hiveserver2未启动就直接使用beeline连接,会出现如下错误:Error: Could not open client transport with JDBC Uri: jdbc:hive2://master:10000/default: java.net.ConnectException: Connection refused (Connectio..._beeline version 2.0.0 by apache hive beeline> !connect jdbc:hive2://master:1