一,java
1、java和c++的区别
1)c++属于静态编译,运行前将源码编译为机器码;java先将源码编译为字节码,运行期解释和动态编译相结合。
2)C++可以将对象分配在堆,栈,常量池中,堆中的对象,需要delete手动删除。java的对象不能在栈中,gc自重删除。
3)利用多态时,C++需要对函数声明virtual进行动态绑定;java自动为动态绑定。
4)C++的成员变量只能在对象生成后赋初值后使用;java可以随时赋值或者不赋值。
二、内存管理
1.java内存模型
1)栈(方法相关):方法执行时会产生一个栈帧,存放局部变量表,出口地址等。栈帧过多时(无限递归),抛出stackoverflowerror;无法申请到足够内存时,抛出outofmemoryerror.线程独有
2)堆(对象相关):线程共享,存放对象实例和对象中的非静态成员变量。无法申请到足够内存时,抛出outofmemoryerror.
3)常量区(hotspot中的永久带,类相关):线程共享,存放已加载的类信息,常量,静态变量,编译后的代码。
2,jvm参数
eclipse.in设置
1)堆内存:JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存 由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70% 时,JVM会减少堆直到-Xms的最小限制。因此一般设置-Xms、-Xmx相等以避免堆内存的自动扩展。
2)非堆内存:JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
3,JVM异常处理实战:OutOfMemoryError
当出现此问题时,通过观察OutOfMemoryError 后面是哪一块的内存的溢出,分别采取措施。
1)堆溢出
通过设置-XX:+HeapDumpOnOutOfMemoryError 或者用jmap软件让JVM在发生内存溢出时自动的生成堆转储快照以便事后进行分析。
利用工具自动分析dump文件(堆转储快照:是一个用来检查Java内存中的对象和数据的文件),对问题定位并分析是由于内存泄露还是内存溢出导致。
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory。如果是内存溢出,参照物理内存适当调大堆参数或者从代码上调整某些对象的生存周期。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。如果是内存泄露,查看GC Root引用链信息,掌握泄漏对象情况,对代码做出修改。
2)栈溢出
栈容量由-Xss设定,栈帧过多时(无限递归),抛出stackoverflowerror;无法申请到足够内存时,抛出outofmemoryerror.
实验表明,单线程情况下,无论是栈帧太大还是-Xss太小,都只会有stackoverflowerror。多线程情况下的会产生outofmemoryerror,因为物理内存减去堆内存和常量区内存就是占内存,这种情况下只能通过减小堆和常量区的内存来解决。
3)常量区溢出
常量区溢出情况会出现在大量的jsp文件(因为jsp要被翻译为servlet类),或者spring的增强类。通过调整参数改变常量区大小。
4,jvm性能检测与故障处理工具(运行时)
命令行工具:jps:可以列出正在运行的虚拟机进程,显示虚拟机执行的主类名称和本地唯一ID。当有多可虚拟机进程时,只有此方法查看。
jstat:监视虚拟机运行状态信息,没有GUI,只有纯文本数据。包括类装载,内存容量,垃圾收集(如执行了多少次gc)等参数。
jinfo:实时查看和调整虚拟机的各项参数。
jmap:生成堆转储快照。
jstack:生成当前线程快照,用以分析后查看各个线程的状态和死锁检测。
可视化工具:
JConsole :内存监控:相当于可视化的jstat;线程检测:相当于可视化的jstack;Mbean:可以使用代码,中间件控制台实现管理功能
VisualVM :功能更强大,除了Jconsile中的故障监视和处理外,还有生成和分析堆转储快照;分析程序性能(Profiling):CPU性能(方法执行的次数耗时)和内存分析(每个方法关联的对象和占用空间);
5,String的内存分布问题


分析 String s = new String("abc");
- 首先在堆(不是常量池)中创建一个包含指定内容的字符串对象,并将字符串引用指向该对象。例如上述代码中,使用new创建字符串s,其会直接在堆中创建一个内容为“abc”的字符串对对象,并将引用s指向该对象。
- 去字符串常量池中查看,是否有包含该内容的对象。
- 若有,则将new出来的字符串对象与字符串常量池中内容相同的对象联系起来。
- 若没有,则在字符串常量池再创建一个包含该内容的字符串对象,并将堆中的对象与字符串常量池中新创建出来的对象联系起来。
三,垃圾收集器
1、可达性分析算法GC ROOT :从栈中或者常量区中的引用变量触发,沿着引用链访问堆中的对象,访问到的做上标记。最后,没有被标记的就是垃圾。
2、System.gc()和Runtime.gc()会做什么事情?
显示调用这两个方法用来提示JVM要进行full gc。但是,立即开始还是延迟进行垃圾回收是取决于JVM的算法。这两个方法完全一样。
finalize()方法什么时候被调用?
在释放对象占用的内存之前,垃圾收集器会调用对象的finalize()方法。一般建议在该方法中释放对象持有的资源。该方法是对象逃逸的最后一次机会。
3、垃圾收集算法:

标记-清除(Mark-Sweep)
此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法会产生内存碎片。
复制(Copying)
此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把还存活对象复制到另外一个区域中。复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间,存活较多的话,复制的成本较高。
jvm的新生代用此算法,把新生代分为一块eden和2块survivor(默认为8:1,可以改变)。第一次gc之前,新产生的对象只存放于eden中,其中一块survivor存放上一次gc存活的对象,另一块survivor空着。第一次gc后,把eden和survivor中的对象复制到空着的survivor中,将eden和一块survivor空出来,如此循环。此方法解决的对半分空间浪费的问题,但survivor空间较小,需要老年代做空间担保。
标记-整理(Mark-Compact)
此算法结合了 “标记-清除”的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把存活对象移向内存的一端并按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。
分代收集算法,新生代和老年代.根据存活周期划分(存活周期是否大于15)。新生代用复制算法。因为老年代中的对象存活率较高,采用标记-清除或者标记-整理。
4、.gc的分类
分为minor GC和full GC,前者只对新生代进行,后者对整个堆进行(其实包括新生代,老年代,永久带)。
当类加载后,会在常量区建立一个java.lang.Class对象,作为访问这个类的外部接口。
2)类加载器与双亲委派模型

http://wangwengcn.iteye.com/blog/1618337
5、反射的原理:就是在运行期间,遇到反射包中的方法时,Java虚拟机(JVM)会检查该类型的Class对象是否已被加载。如果没有被加载,JVM会根据类的名称找到.class文件并加载它。一旦某个类型的Class对象已被加载到内存,就可以用它来产生该类型的所有对象。
通过反射可以在运行期访问编译器并不知道的类,比较灵活,想加载哪些类在配置文件中配好就可以了,不用修改源代码。
泛型,自动装箱,拆箱,循环,集合的变长参数。
五,JVM性能调优(GC调优)
1、JVM性能指标
1)内存占用:应用程序所占用的各部分堆内存(新生代,老年代,永久带)尽可能合理。
2)延迟:JVM最大的延迟是GC,延迟是衡量GC停顿的重要指标。
3)吞吐量:除掉GC所用的时间后,真正执行程序所在总时间的百分比
2、应用程序的部署
单JVM部署:管理开销,内存占用小,但不保证程序的可用性。
多JVM部署:将某个应用程序部署在多个JVM同时运行。
一般情况下,在保证JVM可用性的同时,尽量减少JVM的数量。
3、JVM运行模式
1)Client和Server:参考JIT
2)32/64位JVM:64bit支持更大的内存空间。
注:当以下GC调优后均达不到用户要求的指标时,可以通过改变2,3中的措施,但改变后需要从新调优。
4,GC调优:主要依据于JVM的三个性能指标,根据gc日志信息。
总体原则:1)使Minor GC尽可能多的回收对象,尽量减少full GC。
2)物理内存许可情况下,尽可能增大堆内存。
3)三个性能指标兼顾两个。
5,堆初始内存配置
1)首先利用JVM自动配置的内存大小将应用程序推进到稳定态。此过程可能会发生OutOfMemoryError,解决见2-3
2)活跃数据:应用程序运行于稳定态时,并在多次full GC后,仍存活的对象所占用堆各部分的空间大小。
3)可以通过新生代,老年代,永久带中的活跃数据确定内存初始大小。

1)新生代大小的优化
主要依据于从gc日志中算出的minor GC的平均时间和频率。其中增大新生代大小会减小gc频率,但增大了gc的时间;减小则反之。
改变新生代大小时,尽量保持老年代大小恒定。
2)老年代大小优化
主要依据于从gc日志中算出的full GC的最大延迟时间和频率。其余与新生代相同。
如果传统的老年代收集器无法满足full GC时的指标要求,则使用并行的CMS。
CMS的优化注意CMS的启动时间,根据gc日志判断,如果CMS启动太晚,会触发Stop the world的full GC;如果启动的太早,没有太多垃圾可回收,消耗了系统的资源。
3)Survivor的空间和晋升年龄值优化
