我的世界java下载教程⼿机,⼤⼚⾯试经验分享
1. 垃圾回收机制
Stop-the-World:
JVM由于要执⾏GC⽽停⽌了应⽤程序的执⾏称之为Stop-the-World,该情形会在任何⼀种GC算法中发⽣。当Stop-the-world发⽣时,除了GC所需的线程以外,所有线程都处于等待状态直到GC任务完成。事实上,GC优化很多时候就是指减少Stop-the-world发⽣的时间,从⽽使系统具有 ⾼吞吐 、低停顿 的特点。
2. java运⾏时的内存划分
1. 程序计数器
记录当前线程所执⾏的字节码⾏号,⽤于获取下⼀条执⾏的字节码。
当多线程运⾏时,每个线程切换后需要知道上⼀次所运⾏的状态、位置。
由此也可以看出程序计数器是每个线程私有的。
3. 虚拟机栈
虚拟机栈由⼀个⼀个的栈帧组成,栈帧是在每⼀个⽅法调⽤时产⽣的。
每⼀个栈帧由局部变量区、操作数栈等组成。每创建⼀个栈帧压栈,当⼀个⽅法执⾏完毕之后则出栈。
如果出现⽅法递归调⽤出现死循环的话就会造成栈帧过多,最终会抛出 StackOverflowError。
若线程执⾏过程中栈帧⼤⼩超出虚拟机栈限制,则会抛出 StackOverflowError。
若虚拟机栈允许动态扩展,但在尝试扩展时内存不⾜,或者在为⼀个新线程初始化新的虚拟机栈时申请不到⾜够的内存,则会抛出OutOfMemoryError。
这块内存区域也是线程私有的。
linux解压文件到指定目录4. Java堆
Java 堆是整个虚拟机所管理的最⼤内存区域,所有的对象创建都是在这个区域进⾏内存分配。
可利⽤参数 -Xms -Xmx 进⾏堆内存控制。
when和while的区别口诀这块区域也是垃圾回收器重点管理的区域,由于⼤多数垃圾回收器都采⽤分代回收算法,所有堆内存也分为 新⽣代、⽼年代,可以⽅便垃圾的准确回收。
这块内存属于线程共享区域。
5. ⽅法区
⽅法区主要⽤于存放已经被虚拟机加载的类信息,如常量,静态变量。 这块区域也被称为永久代。
可利⽤参数 -XX:PermSize -XX:MaxPermSize 控制初始化⽅法区和最⼤⽅法区⼤⼩。
6. 元数据区
java下载过程在 JDK1.8 中已经移除了⽅法区(永久代),并使⽤了⼀个元数据区域进⾏代替(Metaspace)。滑块联轴器属于刚性联轴器吗
默认情况下元数据区域会根据使⽤情况动态调整,避免了在 1.7 中由于加载类过多从⽽出现 java.lang.OutOfMemoryError: PermGen。但也不能⽆线扩展,因此可以使⽤ -XX:MaxMetaspaceSize来控制最⼤内存。
7. 运⾏时常量池
运⾏时常量池是⽅法区的⼀部分,其中存放了⼀些符号引⽤。当 new ⼀个对象时,会检查这个区域是否有这个符号的引⽤。
8. 直接内存
直接内存⼜称为 Direct Memory(堆外内存),它并不是由 JVM 虚拟机所管理的⼀块内存区域。
有使⽤过 Netty 的朋友应该对这块并内存不陌⽣,在 Netty 中所有的 IO(nio) 操作都会通过 Native 函数直接分配堆外内存。
设计软件界面的软件它是通过在堆内存中的 DirectByteBuffer 对象操作的堆外内存,避免了堆内存和堆外内存来回复制交换复制,这样的⾼效操作也称为零拷贝。
既然是内存,那也得是可以被回收的。但由于堆外内存不直接受 JVM 管理,所以常规 GC 操作并不能
回收堆外内存。它是借助于⽼年代产⽣的 fullGC 顺便进⾏回收。同时也可以显式调⽤ () ⽅法进⾏回收(前提是没有使⽤ -XX:+DisableExplicitGC 参数来禁⽌该⽅法)。
值得注意的是:由于堆外内存也是内存,是由操作系统管理。如果应⽤有使⽤堆外内存则需要平衡虚拟机的堆内存和堆外内存的使⽤占⽐。避免出现堆外内存溢出。
9. 常⽤参数
通过上图可以直观的查看各个区域的参数设置。
常见的如下:
-Xms64m 最⼩堆内存 64m.
-Xmx128m 最⼤堆内存 128m.
-XX:NewSize=30m 新⽣代初始化⼤⼩为30m.
-XX:MaxNewSize=40m 新⽣代最⼤⼤⼩为40m.recognize的各种形式
-Xss=256k 线程栈⼤⼩。
-XX:+PrintHeapAtGC 当发⽣ GC 时打印内存布局。
-XX:+HeapDumpOnOutOfMemoryError 发送内存溢出时 dump 内存。
新⽣代和⽼年代的默认⽐例为 1:2,也就是说新⽣代占⽤ 1/3的堆内存,⽽⽼年代占⽤ 2/3 的堆内存。
可以通过参数 -XX:NewRatio=2 来设置⽼年代/新⽣代的⽐例。
对象的创建
下图便是 Java 对象的创建过程,我建议最好是能默写出来,并且要掌握每⼀步在做什么。
Step1:类加载检查
虚拟机遇到⼀条 new 指令时,⾸先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引⽤,并且检查这个符号引⽤代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执⾏相应的类加载过程。
Step2:分配内存
在类加载检查通过后,接下来虚拟机将为新⽣对象分配内存。对象所需的内存⼤⼩在类加载完成后便可确定,为对象分配空间的任务等同于把⼀块确定⼤⼩的内存从 Java 堆中划分出来。分配⽅式有 “指针碰撞” 和 “空闲列表” 两种,选择那种分配⽅式由 Java 堆是否规整决定,⽽ Java 堆是否规整⼜由所采⽤的垃圾收集器是否带有压缩整理功能决定。
内存分配的两种⽅式:(补充内容,需要掌握)
选择以上两种⽅式中的哪⼀种,取决于 Java 堆内存是否规整。⽽ Java 堆内存是否规整,取决于 GC 收集器的算法是"标记-清除",还是"标记-整理"(也称作"标记-压缩"),值得注意的是,复制算法内存也是规整的
内存分配并发问题(补充内容,需要掌握)
在创建对象的时候有⼀个很重要的问题,就是线程安全,因为在实际开发过程中,创建对象是很频繁的事情,作为虚拟机来说,必须要保证线程是安全的,通常来讲,虚拟机采⽤两种⽅式来保证线程安全:
CAS+失败重试: CAS 是乐观锁的⼀种实现⽅式。所谓乐观锁就是,每次不加锁⽽是假设没有冲突⽽去完成某项操作,如果因为冲突失败就重试,直到成功为⽌。虚拟机采⽤ CAS 配上失败重试的⽅式保证更新操作的原⼦性。
TLAB: 为每⼀个线程预先在 Eden 区分配⼀块⼉内存,JVM 在给线程中的对象分配内存时,⾸先在 TLAB 分配,当对象⼤于 TLAB 中的剩余内存或 TLAB 的内存已⽤尽时,再采⽤上述的 CAS 进⾏内存分配
Step3:初始化零值
内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这⼀步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使⽤,程序能访问到这些字段的数据类型所对应的零值。
Step4:设置对象头
初始化零值完成之后,虚拟机要对对象进⾏必要的设置,例如这个对象是那个类的实例、如何才能到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运⾏状态的不同,如是否启⽤偏向锁等,对象头会有不同的设置⽅式。
最后
⾯试前⼀定少不了刷题,为了⽅便⼤家复习,我分享⼀波个⼈整理的⾯试⼤全宝典
想获取个⼈⾼清⾯试题的及个⼈也准备了很多⾯试题含答案的资料供你刷!
Java核⼼知识整理
Java核⼼知识
Spring全家桶(实战系列)
其他电⼦书资料
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论