JVM基础知识

JVM种类

  1. Sun公司的HotSpot 是目前使用范围最广的Java虚拟机。

  2. BEA公司的JRockit(原来的 Bea JRockit)电脑软件,系列产品是一个全面的Java运行时解决方案组合。

  3. IBM公司的J9 VM 是一个高性能的企业级 Java 虚拟机。

JVM运行时区域 (HotSpot)

1.堆区(1 this 2 new出来的对象 3 数组) 【 jvm只有一个堆区,并被所有线程共享】【可分为年轻代和年老代】
2.、方法区(1 字符串常量 2 static 3 所有的class)【JAVA8已移除】
3.栈区( 1 基础数据类型 2 方法的形式参数,方法调用完后从栈空间回收 3 引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC) 【 栈内的数据线程之间独立】
4.元空间【JAVA8取代方法区】
5.程序计数器(在JVM的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成)【线程独享】

个人笔记:
方法区又称永久代;堆区分为年轻代和年老代–优化GC回收机制性能
JAVA8后取消了方法区,设置了元空间,区别是,方法区存在于JVM虚拟内存中,元空间存在于本地物理空间中,string的常量池就存在于此,Java1.6 常量池存在于永久代,Java1.7存在于堆区,Java1.8存在于元空间

java7之前,方法区位于永久代(PermGen),永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值,不可变;
java7中,存储在永久代的部分数据就已经转移到Java Heap或者Native memory。但永久代仍存在于JDK 1.7中,并没有完全移除,譬如符号引用(Symbols)转移到了native memory;字符串常量池(interned strings)转移到了Java heap;类的静态变量(class statics)转移到了Java heap。
java8中,取消永久代,方法存放于元空间(Metaspace),元空间仍然与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中
Native memory:本地内存,也称为C-Heap,是供JVM自身进程使用的。当Java Heap空间不足时会触发GC,但Native memory空间不够却不会触发GC。
知乎上:R大神解答:
Oracle JDK7 / OpenJDK 7的HotSpot VM是把Symbol的存储从PermGen移动到了native memory,并且把静态变量从instanceKlass末尾(位于PermGen内)移动到了java.lang.Class对象的末尾(位于普通Java heap内)。
“常量池”如果说的是SymbolTable / StringTable,这俩table自身原本就一直在native memory里,是它们所引用的东西在哪里更有意思。上面说了,7是把SymbolTable引用的Symbol移动到了native memory,而StringTable引用的java.lang.String实例则从PermGen移动到了普通Java heap。
传送门:jdk8之后永久代去哪了?
因和这篇文章说的相同(R说的SymbolTable 即为符号引用,StringTable即字符串常量),故认为此理解正确,即 java7中,存储在永久代的部分数据就已经转移到Java Heap或者Native memory。但永久代仍存在于JDK 1.7中,并没有完全移除。譬如符号引用(Symbols)转移到了native memory;字符串常量池(interned strings)转移到了Java heap;类的静态变量(class statics)转移到了Java heap。

为什么移除永久代?
1、字符串存在永久代中,容易出现性能问题和内存溢出。
2、永久代大小不容易确定,PermSize指定太小容易造成永久代OOM
3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
4、Oracle 可能会将HotSpot 与 JRockit 合二为一。

在JDK1.7中, 已经把原本放在永久代的字符串常量池移出, 放在堆中. 为什么这样做呢?
因为使用永久代来实现方法区不是个好主意, 很容易遇到内存溢出的问题. 我们通常使用PermSize和MaxPermSize设置永久代的大小, 这个大小就决定了永久代的上限, 但是我们不是总是知道应该设置为多大的, 如果使用默认值容易遇到OOM错误。

类的元数据, 字符串池, 类的静态变量将会从永久代移除, 放入Java heap或者native memory。其中建议JVM的实现中将类的元数据放入 native memory, 将字符串池和类的静态变量放入java堆中. 这样可以加载多少类的元数据就不在由MaxPermSize控制, 而由系统的实际可用空间来控制.

为什么这么做呢? 减少OOM只是表因, 更深层的原因还是要合并HotSpot和JRockit的代码, JRockit从来没有一个叫永久代的东西, 但是运行良好, 也不需要开发运维人员设置这么一个永久代的大小。当然不用担心运行性能问题了, 在覆盖到的测试中, 程序启动和运行速度降低不超过1%, 但是这一点性能损失换来了更大的安全保障。

jvm配置

好了,说了这么多是时候讲一下配置JVM内存的几种参数及其如何使用了。
首先,常见参数种类(配置内存):(-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn)、(-XX:PermSize、-XX:MaxPermSize)。可以从列举的方式上看出我的用意,参数的配置是分组的,前者是用来配置堆区的,后者是用来配置非堆区的。
第一组配置参数:-Xms 、-Xmx、-XX:newSize、-XX:MaxnewSize、-Xmn
1、-Xms :表示java虚拟机堆区内存初始内存分配的大小,通常为操作系统可用内存的1/64大小即可,但仍需按照实际情况进行分配。有可能真的按照这样的一个规则分配时,设计出的软件还没有能够运行得起来就挂了。
2、-Xmx: 表示java虚拟机堆区内存可被分配的最大上限,通常为操作系统可用内存的1/4大小。但是开发过程中,通常会将 -Xms 与 -Xmx两个参数的配置相同的值,其目的是为了能够在java垃圾回收机制清理完堆区后不需要重新分隔计算堆区的大小而浪费资源。
一般来讲对于堆区的内存分配只需要对上述两个参数进行合理配置即可,但是如果想要进行更加精细的分配还可以对堆区内存进一步的细化,那就要用到下面的三个参数了-XX:newSize、-XX:MaxnewSize、-Xmn。当然这源于对堆区的进一步细化分:新生代、中生代、老生代。java中每新new一个对象所占用的内存空间就是新生代的空间,当java垃圾回收机制对堆区进行资源回收后,那些新生代中没有被回收的资源将被转移到中生代,中生代的被转移到老生代。而接下来要讲述的三个参数是用来控制新生代内存大小的。
1、-XX:newSize:表示新生代初始内存的大小,应该小于 -Xms的值;
2、-XX:MaxnewSize:表示新生代可被分配的内存的最大上限;当然这个值应该小于 -Xmx的值;
3、-Xmn:至于这个参数则是对 -XX:newSize、-XX:MaxnewSize两个参数的同时配置,也就是说如果通过-Xmn来配置新生代的内存大小,那么-XX:newSize = -XX:MaxnewSize = -Xmn,虽然会很方便,但需要注意的是这个参数是在JDK1.4版本以后才使用的。
上面所述即为java虚拟机对外提供的可配置堆区的参数,接下来讲述java虚拟机对非堆区内存配置的两个参数:
1、-XX:PermSize:表示非堆区初始内存分配大小,其缩写为permanent size(持久化内存)
2、-XX:MaxPermSize:表示对非堆区分配的内存的最大上限。
这里面非常要注意的一点是:在配置之前一定要慎重的考虑一下自身软件所需要的非堆区内存大小,因为此处内存是不会被java垃圾回收机制进行处理的地方。并且更加要注意的是 最大堆内存与最大非堆内存的和绝对不能够超出操作系统的可用内存。

类的加载过程

JVM将类的加载分为3个步骤:
1、装载(Load)

2、链接(Link)(1,验证 2,准备 3,解析)

3、初始化(Initialize)

加载:
1、通过一个类的全限定名来获取其定义的二进制字节流。

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口

验证:确保被加载的类的正确

准备:为类的静态变量分配内存,并将其初始化为默认值

解析:把类中的符号引用转换为直接引用

初始化:1,声明类变量是指定初始值。

2,使用静态代码块为类变量指定初始值。

类的初始化步骤或JVM初始化的步骤如下:
1)如果这个类还没有被加载和链接,那先进行加载和链接 ;

2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口);

3 ) 假如类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。

Java中的类加载大体分为四类:启动类加载器(Bootstrap ClassLoader)扩展类加载器(Extension ClassLoader)应用程序类加载器(Application ClassLoader)用户自定义类加载器(User ClassLoader)

双亲委派机制 启动类加载器-》扩展类加载器-》应用程序类加载器 ,为了保持类加载唯一,所有类加载都会从启动类加载器开始

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值