佛山外贸企业网站建设,wordpress 免费,杭州城乡和住房建设局网站,wordpress 添加版权信息1. 什么是 JVM#xff1f;
Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行#xff0c;Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行。
因此在运行时#xff0c;Java源程序需要通过编译器编译成为.…1. 什么是 JVM
Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行。
因此在运行时Java源程序需要通过编译器编译成为.class文件。
众所周知java.exe是java class文件的执行程序但实际上java.exe程序只是一个执行的外壳它会装载jvm.dllwindows下下皆以windows平台为例linux下和solaris下其实类似为libjvm.so这个动态连接库才是java虚拟机的实际操作处理所在。
JVM是JRE的一部分。它是一个虚构出来的计算机是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
JVM有自己完善的硬件架构如处理器、堆栈、寄存器等还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。
使用JVM就是为了支持与操作系统无关实现跨平台。所以JAVA虚拟机JVM是属于JRE的而现在我们安装JDK时也附带安装了JRE(当然也可以单独安装JRE)。 2. 堆和栈的概念它们有什么区别和联系
在说堆和栈之前我们先说一下JVM虚拟机内存的划分
Java程序在运行时都要开辟空间任何软件在运行时都要在内存中开辟空间Java虚拟机运行时也是要开辟空间的。JVM运行时在内存中开辟一片内存区域启动时在自己的内存区域中进行更细致的划分因为虚拟机中每一片内存处理的方式都不同所以要单独进行管理。
JVM内存的划分有五片
1寄存器
2本地方法区
3方法区
4栈内存
5堆内存。
重点来说一下堆和栈
栈内存栈内存首先是一片内存区域存储的都是局部变量凡是定义在方法中的都是局部变量方法外的是全局变量for循环内部定义的也是局部变量是先加载函数才能进行局部变量的定义所以方法先进栈然后再定义变量变量有自己的作用域一旦离开作用域变量就会被释放。栈内存的更新速度很快因为局部变量的生命周期都很短。
堆内存存储的是数组和对象其实数组就是对象凡是new建立的都是在堆中堆中存放的都是实体对象实体用于封装数据而且是封装多个实体的多个属性如果一个数据消失这个实体也没有消失还可以用所以堆是不会随时释放的但是栈不一样栈里存放的都是单个变量变量被释放了那就没有了。堆里的实体虽然不会被释放但是会被当成垃圾Java有垃圾回收机制不定时的收取。
比如主函数里的语句 int [] arrnew int [3];在内存中是怎么被定义的
主函数先进栈在栈中定义一个变量arr,接下来为arr赋值但是右边不是一个具体值是一个实体。实体创建在堆里在堆里首先通过new关键字开辟一个空间内存在存储数据的时候都是通过地址来体现的地址是一块连续的二进制然后给这个实体分配一个内存地址。数组都是有一个索引数组这个实体在堆内存中产生之后每一个空间都会进行默认的初始化这是堆内存的特点未初始化的数据是不能用的但在堆里是可以用的因为初始化过了但是在栈里没有不同的类型初始化的值不一样。所以堆和栈里就创建了变量和实体
那么堆和栈是怎么联系起来的呢 刚刚说过给堆分配了一个地址把堆的地址赋给arrarr就通过地址指向了数组。所以arr想操纵数组时就通过地址而不是直接把实体都赋给它。这种我们不再叫他基本数据类型而叫引用数据类型。称为arr引用了堆内存当中的实体。可以理解为c或“c”的指针Java成长自“c”和“c”很像优化了“c” 如果当int [] arrnull;
arr不做任何指向null的作用就是取消引用数据类型的指向。
当一个实体没有引用数据类型指向的时候它在堆内存中不会被释放而被当做一个垃圾在不定时的时间内自动回收因为Java有一个自动回收机制而“c”没有需要程序员手动回收如果不回收就越堆越多直到撑满内存溢出所以Java在内存管理上优于“c”。自动回收机制程序自动监测堆里是否有垃圾如果有就会自动的做垃圾回收的动作但是什么时候收不一定。
所以堆与栈的区别很明显
1栈内存存储的是局部变量而堆内存存储的是实体
2栈内存的更新速度要快于堆内存因为局部变量的生命周期很短
3栈内存存放的变量生命周期一旦结束就会被释放而堆内存存放的实体会被垃圾回收机制不定时的回收。 3. Class.forName 和 ClassLoader 有什么区别
在java中对类进行加载可以使用Class.forName()和ClassLoader。 ClassLoader遵循双亲委派模型最终调用启动类加载器的类加载器实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”获取到二进制流后放到JVM中。
Class.forName()方法实际上也是调用的ClassLoader来实现的。
通过分析源码可以得出最后调用的方法是forName()方法方法中的第2个参数默认设置为true该参数表示是否对加载的类进行初始化设置为true时会对类进行初始化这就意味着会执行类中的静态代码块以及对静态变量的赋值等操作。
也可以自行调用Class.forName(String name, boolean initialize,ClassLoader loader)方法手动选择在加载类的时候是否要对类进行初始化。
JDK源码中对参数initialize的描述是if {code true} the class will be initialized大概意思是说当值为true则加载的类将会被初始化。 4. 常用的垃圾收集器有哪些
Serial 收集器新生代
Serial即串行以串行的方式执行是单线程的收集器。它只会使用一个线程进行垃圾收集工作GC线程工作时其它所有线程都将停止工作。
作为新生代垃圾收集器的方式-XX:UseSerialGC
ParNew 收集器新生代
Serial收集器的多线程版本需注意的是ParNew在单核环境下性能比Serial差在多核条件下有优势。
作为新生代垃圾收集器的方式-XX:UseParNewGC
Parallel Scavenge 收集器新生代
多线程的收集器目标是提高吞吐量吞吐量 运行用户程序的时间 / 运行用户程序的时间 垃圾收集的时间。
作为新生代垃圾收集器的方式-XX:UseParallelGC
Serial Old 收集器老年代
Serial收集器的老年代版本。
作为老年代垃圾收集器的方式-XX:UseSerialOldGC
Parallel Old 收集器老年代
Parallel Scavenge收集器的老年代版本。
作为老年代垃圾收集器的方式-XX:UseParallelOldGC
CMS 收集器老年代
CMSConcurrent Mark Sweep收集器几乎占据着JVM老年代收集器的半壁江山它划时代的意义就在于垃圾回收线程几乎能做到与用户线程同时工作。
作为老年代垃圾收集器的方式-XX:UseConcMarkSweepGC
G1 收集器新生代 老年代
面向服务端应用的垃圾收集器在多CPU和大内存的场景下有很好的性能。HotSpot开发团队赋予它的使命是未来可以替换掉CMS收集器。
作为老年代垃圾收集器的方式-XX:UseG1GC 5. 生产环境中应用的 JVM 参数有哪些
-server -Xms6000M -Xmx6000M -Xmn500M -XX:PermSize500M -XX:MaxPermSize500M -XX:SurvivorRatio65536 -XX:MaxTenuringThreshold0 -Xnoclassgc -XX:DisableExplicitGC -XX:UseParNewGC -XX:UseConcMarkSweepGC -XX:UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction0 -XX:CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction90 -XX:SoftRefLRUPolicyMSPerMB0 -XX:PrintClassHistogram -XX:PrintGCDetails -XX:PrintGCTimeStamps -XX:PrintHeapAtGC -Xloggc:log/gc.log 6. 什么情况下会发生栈内存溢出
栈溢出(StackOverflowError)
栈是线程私有的他的生命周期与线程相同每个方法在执行时会创建一个栈帧用来存储局部变量表操作数栈动态链接方法出口灯信息。局部变量表又包含基本数据类型对象引用类型。
若线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError异常。
若虚拟机在动态扩展栈时无法申请到足够的内存空间则抛出OutOfMemoryError异常。 7. 常用的 JVM 调优配置参数有哪些
假设参数为-Xms20m -Xmx20m -Xss256k
XX比X的稳定性更差并且版本更新不会进行通知和说明。
1、-Xms
s为strating表示堆内存起始大小
2、-Xmx
x为max表示最大的堆内存一般来说-Xms和-Xmx的设置为相同大小当heap自动扩容时会发生内存抖动影响程序的稳定性
3、-Xmn
n为new表示新生代大小-Xss规定了每个线程虚拟机栈堆栈的大小。
4、-XX:SurvivorRator8
SurvivorRatio定义新生代中Eden区域和Survivor区域From幸存区或To幸存区的比例默认为8也就是说Eden占新生代的8/10From幸存区和To幸存区各占新生代的1/10。
5、-XX:PretenureSizeThreshold3145728
表示当创建new的对象大于3M的时候直接进入老年代
6、-XX:MaxTenuringThreshold15
表示当对象的存活的年龄minor gc一次加1大于多少时进入老年代
7、-XX:-DisableExplicirGC
表示是否表示是-表示否打开GC日志 8. 什么是类加载器
类加载器是指把类文件加载到虚拟机中通过一个类的全限定名包名类型来获取描述该类的二进制字节流。
类加载器是Java语言的一项创新最开始是为了满足Java Applet的需求而设计的。
类加载器目前在层次划分、程序热部署和代码加密等领域被广泛使用。 9. 类加载器分为哪几类
JVM默认提供了系统类加载器JDK1.8包括如下
Bootstrap ClassLoader系统类加载器
Application ClassLoader应用程序类加载器
Extension ClassLoader扩展类加载器
Customer ClassLoader自定义加载器 10. 可以自定义一个 java.lang.String 吗
答案是可以的但是不能被加载使用。
这个主要是因为加载器的委托机制在类加载器的结构图中BootStrap是顶层父类ExtClassLoader是BootStrap类的子类ExtClassLoader是AppClassLoader的父类。当使用java.lang.String类时Java虚拟机会将java.lang.String类的字节码加载到内存中。
加载某个类时优先使用父类加载器加载需要使用的类。加载自定义java.lang.String类其使用的加载器是AppClassLoader根据优先使用父类加载器原理AppClassLoader加载器的父类为ExtClassLoader这时加载String使用的类加载器是ExtClassLoader但类加载器ExtClassLoader在jre/lib/ext目录下并不能找到自定义java.lang.String类。
然后使用ExtClassLoader父类的加载器BootStrap父类加载器BootStrap在JRE/lib目录的rt.jar找到了String.class将其加载到内存中。 11. Java 中如何判断 JVM 是 32 位 或 64 位
使用sun.arch.data.model或os.arch来获取某系统的属性信息来判断JVM是32位还是64位。 12. Java 中能否保证 GC 执行吗
Java中不能保证GC的执行。
虽然可以通过程序调用System.gc()或者Runtime.gc()方法但是没有办法保证GC的执行。 13. Java 中什么是分区收集算法
分区收集算法就是将整个堆空间划分为连续的不同的小区间region。
每个小区间独立使用独立回收。这种算法的优势是可以控制一次回收多少个小区间。
根据目标停顿时间每次合理地回收若干个小区间而不是整个堆从而减少一次GC所产生的停顿。
分代收集法是目前大部分JVM所采用的方法其核心思想是根据对象存活的不同生命周期将内存划分为不同的域一般情况下将GC堆划分为老生代(Tenured/Old Generation)和新生代(YoungGeneration)。
老生代的特点是每次垃圾回收时只有少量对象需要被回收新生代的特点是每次垃圾回收时都有大量垃圾需要被回收因此可以根据不同区域选择不同的算法。 14. Java 中什么是强引用
强引用是指把一个对象赋值给一个引用变量这个引用变量就是一个强引用Java中最常见的就是强引用。
当一个对象被强引用变量引用时那么是不可能被垃圾回收机制回收的因此强引用是造成Java内存泄漏的主要原因之一。
代码如下
Object obj new Object();
当内存空间不足时Java虚拟机宁可抛出OutOfMemoryError错误使程序异常终止也不会靠随意回收具有强引用的对象来解决内存不足的问题。
当强引用对象不使用时需弱化从而使垃圾回收机制能够回收如下
obj null;
当obj设置为null或超出对象的生命周期范围此时GC会认为这个对象不存在引用就可以回收这个对象。 15. Java 中什么是软引用
软引用可用来实现内存敏感的高速缓存。
软引用需要使用SoftReference类来实现对于只有软引用的对象来说当系统内存足够时不会被垃圾回收器回收但是系统内存空间不足时会被垃圾回收器回收。
软引用通常用来实现内存敏感的高速缓存。
String str new String(abc);
SoftReferenceString softReference new SoftReferenceString(str);
注意的是软引用对象是在JVM内存不不足时才会被回收而调用System.gc()方法只是起到通知作用具体JVM何时扫描回收对象是JVM状态决定的。 16. Java 中什么是弱引用
弱引用需要使用WeakReference类来实现相对比软引用的生命周期更短。
对于只有弱引用的对象来说垃圾回收机制一运行垃圾回收器线程扫描它所管辖的内存区域过程中不管当前内存空间是否足够都会回收它的内存。但是由于垃圾回收器是一个优先级很低的线程因此不一定会很快发现那些只具有弱引用的对象。
String str new String(abc);
WeakReferenceString weakReference new WeakReference(str);
str null;
注意的是如果一个对象是很少使用且希望在使用时随时就能获取到该对象但又不想影响此对象的垃圾收集那么建议使用Weak Reference来记住此对象。 17. Java 中什么是虚引用
虚引用与其他几种引用都不同虚引用不会决定对象的生命周期。如果一个对象仅有虚引用那么就和没有任何引用一样在任何时候都可能被垃圾回收器回收。
虚引用需要使用PhantomReference类来实现不能单独使用必须和引用队列联合使用。虚引用的应用场景是跟踪对象被垃圾回收的状态。
String str new String(abc);
ReferenceQueue queue new ReferenceQueue();// 虚引用必须与一个引用队列关联
PhantomReference pr new PhantomReference(str, queue); 18. Java 中类加载器都有哪些
类加载器按照层次从顶层到底层分为以下三种
1启动类加载器Bootstrap ClassLoader
负责将存放在JAVA_HOME/lib下的或被-Xbootclasspath参数所指定路径中的并且是虚拟机识别的类库加载到虚拟机内存中。
注意的是启动类加载器无法被Java程序直接引用。
2扩展类加载器Extension ClassLoader
负责加载JAVA_HOME/lib/ext目录中的或者被java.ext.dirs系统变量所指定的路径中的所有类库。
注意的是开发者可以直接使用扩展类加载器。
3应用程序类加载器Application ClassLoader
ClassLoader中getSystemClassLoader()方法的返回值所以一般也称它为系统类加载器。
负责加载用户类路径Classpath上所指定的类库可直接使用这个加载器如果应用程序没有自定义自己的类加载器一般情况下该加载器就是程序中默认的类加载器。