上一篇文章中已经写到了运行时数据区的两个程序技术器和虚拟机栈,接下来接着讲运行时数据区的本地方法栈和堆以及方法区等的一系列文章
上一篇文章地址:https://blog.csdn.net/weixin_46635575/article/details/122600822
下一篇地址:https://blog.csdn.net/weixin_46635575/article/details/122730272
一、本地方法接口
本地方法接口不是属于我们运行时数据区的内容,但是它会涉及到后面的内容,所以这里先来补充一下我们的本地方法接口等一系列的概念
1、本地方法
native调用的是一个本地方法,虽然它没有方法体,但是它并不是真的没有方法体的,只是它的方法体是用其他语言写的代码的,而兼溶了其他代码。像我们的abstract修饰符则是没有方法体的。不能比较。
2、为什么要有本地方法呢?
二、本地方法栈
java虚拟机栈是管理java方法的调用,而本地方法栈则是负责调用的是本地方法。它是线程私有的。
三、堆(heap)
首先咱们红色表示的两个是进程共享的(进程就对应了一个虚拟机)
1、堆的核心概念
- 重点之一是它在物理上可以不连续,但是在逻辑上必须连续。(因为可以在虚拟内存层面和物理层面上的内存映射表)
- 另外我的堆虽然是线程共享的,但是它是会在内部存在的一个叫TLAB(缓冲区),它是线程私有的
- JVM就是就是我们的Boostrap类加载器就给我们创建了,JVM创建了后,后续就有很多创建起来了,比如什么堆哦,还有什么程序计数器等都创建起来了。
- 你看下图就是就是你启动项目的时候,此时就创建了个JVM,就相当于一个进程。
- 每一个JVM都都启动了一个进程,我们可以通过jdk自带的查看器进行查看。(如下可以查看一个进程运行情况)
比如启动一个JVM- 没启动之前
- 点击启动后
- 多了一个进程
- 没启动之前
2、对象的创建和GC的概念
- 举例分析一下
- 对象的创建(虽然我们只写了new关键字,但是堆为我们做了很多不用我们做的事情)
这里再复习一下,我们的栈中是不存在GC的,因为我们的栈中是频繁的进行数据的运算等的一些操作,它就是一个进栈和出栈的两个操作,没什么其他的操作的。
3、堆内存的细分结构
咱们java8的内存划分是这样的(咱们java8及之后的版本和之前的java7及之前的区别主要就是我们堆内存的变化,7及之前是永久代,8及以后是元空间)
4、如何设置堆内存大小与OOM
(1)参数使用
-
格式
-
idea和之前写的文章中的虚拟机栈大小设置一样的。
- 在实际开发中的,你的参数Xms和Xmx你可以自定义大小,但是建议设置为初始和最大都设置为一样的值。因为现实中我们开发中,使用线程池什么的,都是一起使用的,那样可以一起扩大,一起减小。
-
这样可以获得你的电脑默认的堆空间大小设置
-
如何显示你内存的划分情况
下面种是这样,至于上面种的话,可以自己去百度一下,写不明白。
(2)OOM说明与举栗子
- 这里来复习一下我们的异常
它有两个继承关系,有Exception和Error。
如果面试官问到你遇见过哪些异常,那你可两个都答出来。
5、年轻代和老年代
- 咱们新生代就是分为如下
- Eden:伊甸园,它是神话的开始亚当和他老伴,上帝就把他们两个放到了Eden,所以它就是新生的象征。
- Survivor1和0:它们在使用的时候只会使用其中的一个,比如我们刚才设置的参数最大堆内存和初始的都是600M,但是它却只有575M可以使用,打印出来也只有575,为什么呢?原因就是因为它回收垃圾的时候进行复制算法实现,用来进行对象的判断回收。同样你可能在有些书里面看到的是他们教to和from区,都是一样的概念
- 参数设置
虽然看上面的是有比例的,但是并并一定是这样的,而它是有一个自适应的机制的,可以把它关掉。后面写了“-”号,-UseAdaptiveSizePolicy,你设置也没有用。
需要进行显示指定大小。
- 下面这个参数一般不设置
- 最后对象的存储过程
6、对象的创建过程
(1)分配过程
- 文字描述:可以看我这篇文章中写到的对象创建,而且建议一定要去看,不要看全部文章,但是可以看一下对创建的对象的描述
- 来看一下我们图解对象的创建
- 第一步:在我们的Eden里面放【当Eden满后,触发YGC/Minor Gc进行回收,具体的判断过程就在后续文章里面写到】 ,当Gc后,任然要的对象就把移动到我们的s0,此时两个对象的年龄都长1
- 第二步:当又进行分配对象后,发现内存不足,又进行回收,然后就把Eden里面的对象放到s1里面,他们的年龄就长1。同时也要把s0里面的进行判断,是否还是需要,需要也移动到s1里面,它的年龄就长1到2了。
这时候的s1就相对于刚才的s0区,它现在叫s0了,刚才的那个s0叫s1了。【就相当于谁空谁是s1区】 - 同样的,也要进行判断,移动。就这样持续下去。
- 当当当。年龄计数器到了15【叫做域值,它是默认的大小为15,它可以用参数-XX:MaxTenuringThreshold=进行设置】后,大于十五后,就要把它移动到老年代了
- 补充一点,当我们的s0或者s1满后,是不会触发垃圾回收的,只有当Eden进行触发后,它才会被进行被动的回收。但是我们的s1或s0它可能会直接没有年龄到达15就去了老年代的特殊情况。而也有中例外的是,有可能新生对象刚出来就蹦到了老年代的。
- 第一步:在我们的Eden里面放【当Eden满后,触发YGC/Minor Gc进行回收,具体的判断过程就在后续文章里面写到】 ,当Gc后,任然要的对象就把移动到我们的s0,此时两个对象的年龄都长1
(2)总结两句话
老年代一般不会进行回收的原因是,它都经过一层层的选拔,它一般都是有重要作用的,肯定不会一般情况去动它的,还有一个原因就是老年代的空间足够的大,一般不会触发垃圾回收机制的。
(3)对象分配的特殊情况
上面这种情况是说你不让让自动调整内存大小的情况。