高级Java知识
高级Java知识(JVM、字节码、内存模型)
内存=方法区+栈空间+堆+程序计数器
栈(stack)包括虚拟机栈(VM stack)和本地方法栈(native method stack)。
方法区(method area)内放置 类信息(Class)、常量、静态变量、JIT编译后代码。
运行时常量池是方法区的一部分。
Class文件有一个常量池(Constant Pool Table),属于Class的一部分。
运行时常量池(Runtime Constant Pool)属于method area的一部分。
线程请求的栈容量大于VM允许的最大容量将引发StackOverflowError。
JVM规范允许虚拟机栈(如Hotspot虚拟机允许本地方法栈归入VM栈)动态扩展,若果在扩展时申请不到更多的内存,将引发OutOfMemoryError。
堆上申请不到更多内存将引发OOM error。
运行时常量池申请不到更多内存将引发OOM Error。
直接内存(Direct Memory)?也可能导致OOM。
new 过程: 寻找new 参数(需要被new的类)是否在常量池中、是否被加载、解析、初始化。
指针碰撞(bump the pointer)是认为内存是规整的,使用过的内存存在于(逻辑)连续的空间,用一个指针分割可用内存和已使用内存。
空闲列表(free list)是用列表记录空闲内存块。
对象头信息(object header)主要分两部分,一是类元数据指针(如果栈上reference通过句柄定位对象和类型数据,则没有类元指针),另一部分是对象hash、gc分代年龄、锁等自身运行时信息,如果是数组,还有数组大小信息。
分配内存、设置object header,初始化对象方法
对象在内存中分3块区域:object header, instance data, padding.
栈上reference定位对象有两种方式,一是句柄,二是直接指针。句柄是一种间接指针,该reference指向堆中句柄池中的一个句柄,句柄中存放对象实例数据指针和类型数据指针。直接指针则存放了包含类元数据指针的对象数据指针。
句柄定位方式优势在于对象在内存中被移动时(GC时被移动是很普遍的)栈上reference保持不变。直接指针优势是访问快。Sun HotSpot VM采用后者定位方式。
JVM参数:
- -Xss:栈大小
- -Xoss: native method stack,对Hotspot VM无效(其不区分vm stack、native method stack)
- -Xmx:堆最大内存量 -Xms:堆最小内存量
- -XX:PermSize=10M 永久代(位于方法区中)大小
- -XX:MaxPermSize=10M 永久代最大容量
jdk 1.7逐步去“永久代”,1.8完全去除。上述vm参数无效。
jvm运行时检测到的经常被抛出的jdk内置异常(NPE),可在其被抛出一定次数后优化其stacktrace为空,通过jvm开关OmitStackTraceInFastThrow设置。 - -XX:+OmitStackTraceInFastThrow 打开优化。
- -XX:-OmitStackTraceInFastThrow 关闭优化。
- -verbose:class -XX:+TraceClassLoading
- -XX:+TraceClassUnLoading关于类加载、卸载信息的vm参数。
运行时JVM会对经常被抛出的JRE预定义异常进行输出优化——将其stacktrace置为空,减少性能损失,所以可能看到一个异常(如NPE)被抛出,但其堆栈信息为空。
引用计数算法无法解决循环引用问题,objA.x=objB; objB.y=objA;objA=null;objB=null; 由于相互引用导致两个计数都不为0,但实际两个都应该被GC。
可达性分析GC策略:能通过GC roots可达的对象是存活对象。
GC Roots包括以下对象:
- VM栈(栈帧中本地变量表)中的引用对象
- 方法区中静态对象
- native方法中引用的对象
引用:强引用(Strong)、软引用(soft)、弱引用(weak)、虚引用(phantom)。强度依次减弱。
软引用:还有用但并非必需。在内存不够用(将要溢出前)才会回收这些引用。
弱引用:弱引用不影响GC,但对象只有弱引用时会被正常GC。
虚引用:完全不影响GC,唯一目的是在此对象被GC时能收到一条系统通知。
GC:GC roots不可达且有必要执行finalize()方法(对象重写了finalize且没有被vm调用过) -> 第一次标记,并放到F-Quene -> 低优先级执行F-Quene中对象的finalize(但不保证执行完该方法因其运行慢或死循环) -> finalize期间对象没有将this指向其他gc roots可达对象的字段:回收;否则不回收。
注:任一对象的finalize只被执行一次,即使再次面对GC。遵从建议:让我们忘了这个方法吧。
方法区的回收是针对无用常量和类。
GC算法:
- Mark-sweep 标记清除。标记需要回收的对象,标记完后同意清除。不足:标记和清除效率都不高;清除后产生大量零碎、不连续内存空间。
- copying 复制。 Eden空间+两块Survivor空间。Eden:Survivor=8:1,回收eden,将其中存活对象复制到survivor空间,清除eden。缺点:如果对象存活率高,则导致过多复制而降低gc性能;由于10%的survivor空间不能保证一定能容纳所有存活对象,需要额外空间保证。
- mark-compact 标记-整理。老年代中对象存活率很高,复制算法导致过多复制以及额外空间。标记-整理算法在gc时将存活对象整理到内存空间的一端连续存放,直接清理另一端内存。
- Generational Collection 分代收集。将内存分为新生代和老年代,根据特点使用copying、mark-sweep/mark-compact算法。
GC器:
- serial。 单线程,新生代用copying、老年代用mark-compact算法,准备收集时会“stop the world”。
- ParNew。serial的多线程版
- Parallel Scavenge。新生代收集器。关注点是可控的吞吐量(user-time / (user-time + gc-time)),而CMS等GC器关注GC时导致的停顿时间。该GC器可自适应调节新生代大小(—Xmn)、eden与survivor比例(_XX:SurvivorRatio)、晋升老年代年龄(-XX:PretenureSizeThreshold)。
- Serial Old。Serial的老年代版本。
- Parallel Old。Parallel Scavenge的老年代版本,使用mark-compact算法。
- CMS(Concurrent Mark Sweep)。并发GC、低停顿时间。 a. 初始标记(gc roots直接关联的对象,stop the world) b. 并发标记(gc roots tracing,与用户线程同时工作) c. 重新标记(并发标记期间产生的变动,stop the world) d. 并发清除。
- G1(Garbage First)。优点:a. 并行、并发;b. 分代收集;c. 内存碎片整理;d. 可控的停顿时间。思想:内存分为大小相同的若干region,优先回收价值(获得的内存空间/所需时间)大的garbage。
JVM工具
jps -l 显示jvm进程信息
jstack [-F 强制输出堆栈; -l 锁信息; -m native方法堆栈] pid
VisualVM(jvisualvm): btrace插件,热机跟踪。jvisualvm在jdk9+后不再默认提供。
(hotspot)JVM引擎会复用局部变量表slot,对GC影响的例子如下:
// VM参数: -verbose:gc
void main(){
{
byte[] mem=new byte[64*1024*1024];
}
// int a=0; 无此代码行时尽管mem已不能被访问,但不会被回收,当启用此代码时由于再次访问了局部变量表,将导致$mem的内存被回收
System.gc();
}
方法正常完成退出、方法异常完成退出。后者需要异常处理器表帮助方法返回、继续执行程序。
字节码指令集
invokestatic: 调用静态方法
invokespecial: , private, 父类方法。
invokevirtual: 虚方法(除被invokestatic, invokespecial指令调用的方法即static, , private, 父类方法的方法)及final方法。
invokeinterface:
invokedynamic:
非虚方法(static、、private、父类方法、final方法)在类加载时即可被解析为直接引用。final非虚方法由invokevirtual指令调用。
java是静态多分派、动态单分派的语言。
类加载
编译器会为类生成方法,接口的只有在常量初始化时才会被生成。
类执行前一定先执行父类,不会执行类接口的。
类只会被初始化一次,类中(静态初始化过程中)应避免过长的执行时间,否则会导致阻塞与此类有关其他线程。
类的Class依赖于类加载器,不同类加载器加载同一份类字节码得到的Class一定不一样。两个类的“相等”比较只有在类被同一个加载器加载的情况下有意义(否则一定不相等),这里的相等包括,Class<?>.equals, isAssignableFrom, inInstance, instanceof。
boostrap classloader <- ext classloader <- application classloader(system classloader) <- user classloader
高级Java知识的更多相关文章
- [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推)
[原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推) 内部推荐职位 高级JAVA技术经理: 岗位职责: 负责项目管理(技术方向),按照产品开发流 ,带领研发团队,制定 ...
- 如何成为高级java程序员
或许您已经读过我的那篇小文<如何成为java初级程序员>,那里面只介绍了成为一个JAVA程序员应该具备的一些知识.我相信您绝不会只想着做一个初级的程序员,上了软件开发的小船,您肯定有着远大 ...
- Java知识回顾 (1) 编译环境与基本变量类型
参考资料 runoob Java知识回顾序列的相关资料,主要来自 runoob,并对其中的知识进行概况或总结,去除对一个之前了解过Java的人员无关的知识点.以便能够使得一个新手,或之前有Java经验 ...
- 互联网高级Java面试总结
前不久刚换了单位,这段时间抽出时间来总结一下. 本人渣本毕业四年,无大厂工作经验,出来面高级Java. 上家单位是一个知名互联网平台,但是体量不大的小公司(5线互联网公司),但就是出名(职场人都知道~ ...
- 高级Java必看的10本书
1.深入理解Java虚拟机:JVM高级特性与最佳实践 本书共分为五大部分,围绕内存管理.执行子系统.程序编译与优化.高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理. 2. ...
- Java知识体系
Java知识体系 java知识结构.jpg web框架.jpg 计算机课程体系.png 2016-08-19_090929.png 流行的哈希算法生存状况.jpg "JAVA之父" ...
- [转]20个高级Java面试题汇总
http://saebbs.com/forum.php?mod=viewthread&tid=37567&page=1&extra= 这是一个高级Java面试系列题中的第一部分 ...
- 20个高级Java面试题
这是一个高级Java面试系列题中的第一部分.这一部分论述了可变参数,断言,垃圾回收,初始化器,令牌化,日期,日历等等Java核心问题. 程序员面试指南:https://www.youtube.com/ ...
- 高级java高并发,高性能,分布式,高可用,负载均衡,系统架构实战
java架构师.集群.高可用.高可扩 展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布 式项目实战 视频课程包含: ...
随机推荐
- TortoiseGit推送失败的问题
网络的SSH修改为使用git默认的ssh客户端,而不是tortosieGit提供的客户端 修改成这样 下面的本机凭证修改为当前用户 然后直接使用右键->git同步 在推送url上填写远程的url ...
- 夜话JAVA设计模式之适配器模式(adapter pattern)
适配器模式:将一个类的接口,转换成客户期望的另一个接口,让不兼容的接口变成兼容. 1.类适配器模式:通过多重继承来实现适配器功能.多重继承就是先继承要转换的实现类,再实现被转换的接口. 2.对象适配器 ...
- 一篮子苹果,每天吃一半多一个吃,第十天吃一半多一个后就剩余一个,求一共多少个苹果,JAVA版
/** * @author xuzhu **/public class TestApple { public static void main(String[] args) { int days = ...
- MySQL基于域名做高可用切换(Consul初试)
一,Consul功能介绍 服务发现 - Consul的客户端可用提供一个服务,比如 api 或者mysql ,另外一些客户端可用使用Consul去发现一个指定服务的提供者.通过DNS或者HTTP应用程 ...
- Ubuntu 16.04粘贴板增强工具Parcellite
默认在Ubuntu已经有粘贴板增强工具,比如保存最近五个的复制文本历史. 1.系统默认 使用:[Ctrl]+[;] 然后用数字进行选择即可,但是只支持文本,只能保存最近5次 2.安装Parcellit ...
- 每日五题(jsp)
1.forward 和 redirect 的差别 答: 1.从地址栏显示来说 forward是server请求资源,server直接訪问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容 ...
- 使用DBMS_REDEFINITION在线切换普通表到分区表
随着数据库数据量的不断增长,有些表须要由普通的堆表转换为分区表的模式.有几种不同的方法来对此进行操作.诸如导出表数据,然后创建分区表再导入数据到分区表.使用EXCHANGE PARTITION方式来转 ...
- STM8S PWM 应用 呼吸灯
//主功能接受:使用MCU STM8S105C6 的PWM通道2 PC2 来做呼吸灯 已经验证OK,呵 //呵,这个PWM设置刚開始用还是有点麻烦,由于是自己摸索.花点时间.还是解决了 . //所用子 ...
- javascript 数组总结
数组的创建: 数组可以使用Array构造函数来创建,或者使用[]快速创建. 1. Array构造函数创建数组: 无参数,创建空数组: var arry = new Array(); 参数为一个数字,指 ...
- dotnet core 文档链接
The installation was successful The following were installed at C:\Program Files\dotnet • .NET Core ...