JAVA JVM 基础理解 (二)

9、怎么打破双亲委派模型

打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法

10、导致Full GC 一般由于以下几种情况:

1)新生代设置过小

​ 一是新生代GC次数非常频繁,增大系统消耗;

​ 二是导致大对象直接进入就剩带,占据了就剩带的剩余空间,诱发GC

2)新生代设置过大

​ 一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发Full GC;二是新生代GC耗时大幅度增加

3)Survivor设置过小

导致对象从eden直接到达旧生代

4)Survivor设置过大

导致eden过小,增加了GC频率

一般说来新生代占整个堆1/3比较合适

GC策略的设置方式

1)吞吐量优先 可由-XX:GCTimeRatio=n来设置

2)暂停时间优先 可由 -XX:MaxGCPauseRatio=n来设置

11、Minor GC, Full GC 触发条件

Minor GC触发条件:当Eden区满时,触发Minor GC

Full GC触发条件:

1)调用System.gc 时,系统建议执行Full GC,但是不必然执行

2)老年代空间不足

3)方法区空间不足

4)通过Minor GC 后进入老年代的平均大小大于老年代的可用内存

5)由Eden区、From Space 区向To Sp3ace 区复制时,对象大小大于To Space可存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。

12、JVM性能调优

1.设定堆内存大小

-Xmx:堆内存最大先知。

2.设定新生代大小。新生代不宜太小,否则会有大量对象涌入老年代

-XX:NewSize: 新生代大小

-XX:NewRatio 新生代和老生代占比

-XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

3.设定垃圾回收器 年轻代用 -XX:UseParNewGC 年老代用 -XX:+UseConcMarkSweepGC

13、Java内存模型

Java 内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行通过.JMM内部的实现通常是依赖于所谓的内存屏障,通过禁止某些重排序的方式,提供内存可见性保证,也就是实现了各种happen-before规则。

与JVM内存模型不同。

Java内存模型即Java Memory Model,简称JMM. JMM定义了Java 虚拟机(JVM)在计算机内在(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。

JAVA内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。

Java线程之间的通信采用的是过共享内存模型,这里提到的共享内存模型指的就是Java内存模型(JMM),JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读、写共享变量的副本。

14.Java中堆和栈有什么区别?

最主要的区别就是栈内存用来存储局部变量和方法调用。

而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中。

独有还是共享

栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其线程中可见,即栈内存可以理解成线程的私有内存。而堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。

异常错误

如果栈内存没有可用的空间存储方法调用和局部变量,JVM会抛出java.lang.StackOverFlowError.

而如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError

空间大小

​ 栈的内存要远远小于堆内存,如果使用递归的话,那么栈很快就会被充满,如果没有及时跳出,很可能发生StackOverFlowError问题。

15.常见的垃圾回收算法有哪些?简述其原理

GC最基础的算法有三种:标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收期一般都采用分代收集算法。

标记 - 清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。

复制算法,“复制”(copying)的收集算法,它将可用内存按照容量划分为大小相等的两块,每次只使用其中一块,当这一块的内存用完了,就将还存活着的对象赋值到另外一块上面,然后再把已使用过的内存空间一次清理掉。

标记-压缩算法,标记过程仍然与“标记-清楚”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存分代收集算法,“分代收集”算法,把Java堆分为新生代和老年代,这样就可以根据各个年代特点采用最适当的手机算法。

16.解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法

通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的占空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor 和 To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据。程序中的字面量(Literal)如直接书写的100、“hello”和常量都是放在常量池中。常量池是方法区的一部分。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足。则会引发OutOfMemoryError。

17.什么是类的加载

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建java.lang.Class对象,用来封装类在方法区内的数据结构,类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

18.类加载器

启动类加载器:Bootstrap ClassLoader ,负责加载存放在 JDK\jre\lib(JDK代表JDK安装的目录)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库。

扩展类加载器:Extension ClassLoader, 该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。

应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器。

19.Java对象创建过程

1.JVM遇到一条新建对象的指令时首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用。然后加载这个类

2.为对象分配内存。一种办法“指针碰撞”、一种办法“空闲列表”,最终常用的办法“本地线程缓冲分配(TLAB)”

3.将除对象头外的对象内存空间初始化为0

4.对对象头进行必要设置

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值