源码分析:java堆的创建-java开发java经验技巧

源码分析:java堆的创建-java开发java经验技巧

ID:30854066

大小:506.87 KB

页数:17页

时间:2019-01-04

上传者:U-991
源码分析:java堆的创建-java开发java经验技巧_第1页
源码分析:java堆的创建-java开发java经验技巧_第2页
源码分析:java堆的创建-java开发java经验技巧_第3页
源码分析:java堆的创建-java开发java经验技巧_第4页
源码分析:java堆的创建-java开发java经验技巧_第5页
资源描述:

《源码分析:java堆的创建-java开发java经验技巧》由会员上传分享,免费在线阅读,更多相关内容在工程资料-天天文库

源码分析:Java堆的创建-编程开发技术源码分析:Java堆的创建丿京文出处:iceAetcma虚拟机在内存中申请一片区域,由虚拟机自动管理,用來满足应用程序对象分配的空间需求,即堆空间。由于程序运行的局部特性,程序创建的大多数对象都具有菲常短的生命周期,而程序也会创建一些生命周期特别长的对象。简单的复制收集器无论对象的生命周期是长是短,都会进行复制操作。而生命周期较长的对象在多次垃圾回收期间内并不会被冋收,这就使得这些对象被來冋复制而使得算法性能大大下降。分代收集把堆分为多个了堆,分别用来存放不同寿命的对象。新生对象空间的将经丿力最频繁的垃圾回收,而对丁经丿力了若干次垃圾收集后仍然存活的对象,将成长为成熟对彖,并移动到成熟对象的子堆中,而对老生代子堆的垃圾冋收就不会像新生对象子堆那么频繁。HotSpot的堆空间分为新生代(YoungGen)和老年代(OldGen,此外还冇位于非堆空间的永久代,但在Java8中将移除永久代),新生代又分为Eden区和2个Survivor区(From/To)用以进行复制收集垃圾对彖。对Java堆和对彖的分析将从Java堆的创建开始,然后分析Java对彖的分配与垃圾回收。一、堆的实现方式在虚拟机的创建初始化过程屮,通过调用Universe的成员函数initialize_heap()将完成Java堆的初始化。在Universe模块下的初始化将根据虚拟机选项来选择堆的具体实现方式:1.若虚拟机配置UseParallelGC,则Java堆的堆类型为ParallclScavcngcIIcap(并行收集堆)//hotspot/sre/share/vm/memory/universe・epp屮if(UseParallelGC){#ifndefSERIALGCUniverse::_collectedHeap二newParallelScavengeHeapO;#else//SERIALGCfatal(z,UseParallelGCnotsupportedinjavakernelvm.〃); #endif//SERIALGC 2•若虚拟机配置UseGIGC,那么将选择堆类型为GlCollectedHeap,垃圾收集策略将使用专用的GlCollectorPolicy(垃圾优先收集)策略elseif(UseGIGC){ttifndefSERIALGCGlCollccto^Policy*glp=newGlCollcctorPolicyBcstRcgionsFirst();GlCollectedHeap*glh=newGlCollectedHeap(glp);Universe::_collectedHeap二glh;#else//SERTALGCfatal("UseGIGCnotsupportedinjavakernelvm.〃);itendif//SERIALGC3.否则,虚拟机将使用GenCol1ectedHeap(分代收集堆)Universe::_collectedHeap二newGenCol1ectedHeap(gc_policy);各个堆实现类的类关系如下:对于默认情况下的堆实现,还耍根据配置选择垃圾回收策略gc_policy来构造一个GenCollectedHeap,这里根据虚拟机配置选择不同的GC策略:(1)・若虚拟机配置UseSerialGC,那么将使用MarkSweepPolicy(标记-清除)策略GenCollectorPolicy*gc_policy;if(UseSerialGC){gc_policy二newMarkSweepPolicy();}~(2).若虚拟机配置UscConcMarkSwccpGC和UscAdaptivcSizcPolicy,那么将使用ASConcurrcntMarkSwccpPolicy(ill适应并发标记-清除)策略,若没有指定 UseAdaptiveSizePolicy,虚拟机将默认使用ConcurrentMarkSweepPolicy(并发标记-清除)策略elseif(UseConcMarkSweepGC){ttifndefSERIALGCif(UscAdaptivcSizcPolicy){gcpolicy=newASConcurrentMarkSweepPolicy();}else{gc_policy=newConcurrentMarkSweepPolicy();}-(1)•若没冇进行配置,虚拟机将默认使用MarkSweepPolicy策略else{//defaultoldgenerationgcpolicy=newMarkSweepPolicy();}~如下表所示:虔拟机配置参数内存堆实現回收策略UseParallelGCParallelScavengerHeapGenerationSizerUseGIGCGlCollectedHeapGlCollectorPolicyUseSerialGCGenCollectedHeapMarkSweepPolicyUseComcMarkSweepGCUseAdaptiveSizePolicyASConcurrentMarkSweepPolicy默认ConcurrentMarkSweepPolicy默认MarkSweepPolicy其屮垃圾回收策略类的关系如下图: CollectorPolicyGenCollectorPolicyTwoGenerationCollectorPolicyMarkSweepPolicyConcurrentMarkSweepPoiicyASConcurrentMarkSweepPolicy3.接下来是相应实现的堆的初始化jintstatus=Universe::heap()->initialize();if(status!二JNI_0K){returnstatus;5•堆空间初始化完成后,是LP64平台上的指针压缩以及TLAB的相关内容。通常64位JVM消耗的内存会比32位的大1.5倍,这是因为在64位环境下,对彖将使用64位指针,这就增加了一倍的指针占用内存开销。从JDK1.6updateM开始,64bitJVM正式支持了-XX:+UseCompressedOops选项来压缩指针,以节省内存空间。指针压缩的地址计算如2addr=+<<3+若堆寻址空间小于4GB(2,2)吋,直接使用32位的压缩对象指针〈narrow_oop>就可以找到该对象若堆寻址空间大于4GB(2^32)但小于32GB时,就必须借助偏移來获得真正的地址(对象是8字节对齐的)。若堆寻址空间大于32GB时,就需要借助堆的基址来完成寻址了,为堆的基址,为一页的大小。(1)•若heap的地址空间的最大地址大于OopEncodingHeapMax(32GB),则设置基 础地址为当前堆的起始地址-页大小,设置偏移为LogMinObjAlignmentlnBytes(3),即使用普通的对彖指针压缩技术if((uint64_t)Universe::heap()->reserved_region().end()>OopEncodinglleapMax){//Can,treserveheapbelow32Gb.Universe::set_narrow_oop_base(Universe::heap()->base()-os::vm_page_size());Universe::set_narrow_oop_shift(LogMinObjAlignmenlTnBytes);}"(2)・否则设置基础地址为0else{Universe::set_narrow_oop_base(0);//...~~}若heap的地址空间的最大地址大于NarrowOopHcapMax(4GB,小于32GB),则设置偏移为LogMinObjAlignmentlnBytes(默认为3),即使用零基压缩技术,否则设置偏移为0,即直接使用压缩对象指针进行寻址if((uint64_t)Universe::heap()->reserved_region().end()>NarrowOopHeapMax){//Can,treserveheapbelow4Gb.Universe::set_narrow_oop_shift(LogMinObjAlignmentlnBytes);}else{Universe::set_naiTow_oop_shift(0);二、堆的初始化:分代实现方式接卜来分析特定堆的初始化过程,这里以GcnCollcctcdHcap和MarkSwccpPolicy为例:GenCollectedHeap的构造函数中使用传入的策略作为_gen_policy(代策略)。以MarkSweepPolicy为例,看看其构造函数://定义在/hotspot/src/share/vm/memory/collectorPolicy.cpp中MarkSwccpPolicy::MarkSwccpPolicy(){initialize_all();}"MarkSweepPolicy的构造函数调用了initialize_all0来完成策略的初始化,initialize_all()是父类GenCollectorPolicy()的虚函数,它调用了三个子初 始化虚函数,这三个子初始化过程由GenCollectorPolicy的子类实现。其中initialize_flags()初始化了永久代的一些大小配置参数,initialize_size_info()设置了Java堆大小的相关参数,initialize_generations()根据用户参数,配置各内存代的管理器。//hotspot/src/share/vm/memory/collcctorPolicy・hpp屮virtualvoidinitializeall(){initialize_flags();iniIialize_size_info();initialize_generations();下面通过initialize_generations()来看看各代有哪些实现方式:1•若配置了UseParNewGC,并且并行GC线程数大于1,那么新生代就会使用ParNew实现◎//永久代初始化generations=newGenerationSpecPtr[number_of_generations()];7/...~if(UscParNcwGC&&ParallclGCThrcads>0){_generations[0]=newGenerationSpec(Genegation::ParNew,initialgenOsize,maxgenOsize);"}""""2.默认新生代使用DefNcw实现else{generations[0]=newGenerationSpec(Generation::DefNew,initialgenOsize,maxgenOsize);"}""""3.老年代固定使用MarkSwccpCompact实现generations[l]=newGenerationSpec(Generation::MarkSweepCompact,_initial_genl_size,_max_genl_size);(其中DefNew>ParNew>MarkSweepCompact等均为Generation的枚举集合Name的成员,描述了可能实现的各种代实现类型)MarkSwccpPo1icy、ConcurrcntMarkSwccpPolicy>ASConcurrcntMarkSwccpPolicy对各代的实现综合如下表所示: 回收策略Young内存代管理罟MarkSweepPolicyUseParNewGCParallelGCThreads>0ParNewGeneration默认DefNewGeneration默认ConcurrentMarkSweepPolicyUseParNewGCParallelGCThreads>0ParNewGenerationDefNewGeneration默认ASConcurrentMarkSweepPolicyUseParNewGCParallelGCThreads>0ASParNewGeneration默认DefNewGeneration默认OlTenConcurrentASConcurrer三、堆的初始化:堆内存空间分配分析完了构造函数,冋到Universe模块中堆的initialize。。以GenCol1ectedHeap为例:1.根据构造函数传入的gc_policy(分代策略)來初始化分代数///fe5Cffi/hotspot/src/share/vm/memory/genCollectedHeap・cpp屮jintGenCollectedHeap::initialize(){//...ngens二genpolicy()->number_of_generations();根据GenCollectedHeap的定义可以看到,GenCollectedHeap最多支持10个分代enumSomeConstants{maxgens二10};"//...private:int_n_gens;Generation*gens[maxgens];其实并不需要这么多分代,MarkSwccpPolicyConcurrcntMarkSwccpPolicyASConcurrentMarkSweepPolicy(ConcurrentMarkSweepPolicy的子类)均冇着共同的祖先类TwoGenerationCollectorPolicy,其分代只有2代,即新生代和老年代。2.每代的大小是基于GenGrain大小对齐的//Theheapmustbeatleastasalignedasgencrations.size_talignment=Generation::GenGrain; GenGrain/^5C^/hotspot/src/share/vm/memory/generation.h屮,在非ARM平台中是2J6字节,即64KB大小1.获取各分代的管理器指针数组和永久代的管理器指针,并对齐各代的大小到64KBPcrmancntGcncrationSpcc*permgenspec=collector_policy()->permanent_generation();//Makesurethesizesareallaligned.for(i=0;ialign(alignment);}""perm_gen_spec->align(alignment);GenerationSpec的align()定义在/hotspot/src/share/vm/memory/generationSpec.h,使初始和最人大小值向上对齐至64KB的倍数//Alignmentvoidalign(size_talignment){set_init_size(align_size_up(init_size(),alignment));set_max_size(align_size_up(max_size(),alignment));}4•调用allocate()为堆分配空间,其起始地址为heapaddresschar*heapaddress;size_ttotal_reserved二0;intn_covered_regions二0;RcscrvcdSpacchcap_rs(0);heapaddress=allocate(alignment,perm_gen_spec,&totalreserved,&n_covered_regions,&heaprs);3.初始分配所得的空间将被圭寸装在_reserved(Col1ectedHeap的MemRegion成员)中_reserved=MemRegion((HeapWord*)heaprs.base(),(HeapWord*)(heap_rs.base()+heap_rs.size()));调整实际的堆大小为去掉永久代的misc_data和misc_code的空间,并创建一个覆盖整个空间的数组,数组每个字节对血于堆的512字节,用于遍历新生代和老年代空间 _reserved.set_word_size(0);reserved.set_start((HeapWord*)he3p_rs.base());size_tactual_heap_size二heaprs.size()-perm_gen_spec->misc_data_size()perm_gen_spec->misc_code_size();reserved.set_end((HeapWord*)(henprs.base()+actualheapsize));_rem_set=col1ector_policy()->create_rem_set(.reserved,n_covcrcd_rcgions);set_barrier_set(rem_set()->bs());7.调用heap_rs的的fir、st_par、t(),依次为新生代和老年代分配空间并调用各代管理器的init()将其初始化为Generation空间,最后为永久代分配空间和进行初始化_gch二this;for(i=0;i<_n_gens;i++){ReservedSpacethisrs=heaprs.first_part(_gen_specs[i]->niax_size(),UseSharedSpaces,UscSharcdSpaccs);_gens[i]=_gen_specs[i]->init(this_rs,i,rem_set());heaprs=heaprs.last_part(_gen_specs[i]->max_size());}""_perm_gen=perm_gen_spec->init(heap_rs,PermSize,remset());四、内存空间申请实现那么GenCollectedHeap是如何向系统申请内存空间的呢?答案就在allocateO函数中1.在屮请Z前,当然要对内存空间的大小和分块数进行计算(1).内存页的大小将根据虚拟机是否配置UseLargePages而不同,large_page_size在不同平台上表现不同,x86使用2/4M(物理地址扩展模式)的页夭小,AMD64使用2M,否则,Linux默认内存页大小只有4KB,接下来会以各代所配置的最大大小进行计算,若最犬值设置为负数,那么jvm将报错退出,默认的新生代和老年代的分块数为1,而永久代的分块数为2char*GenCollectedHeap::allocate(size_talignment,PermanentGenerationSpec*permgenspec, sizet*totalreserved,int*_n_covered_regions,ReservedSpace*heaprs){//…//Nowfigureoutthetoteilsize.sizettotalreserved=0;intn_covered_regions=0;constsize_tpageSize二UseLargePages?os::1arge_page_size():os::vm_page_size();for(inti=0;i<_n_gens;i++){totalreserved+二_gen_specs[i]->max_size();if(total_reserved<_gen_specs[i]->inax_size()){vmexit_during_initialization(overflowmsg);}"""n_covered_regions+二_gen_specs[i]->n_covered_regions();}""加上永久代空间的大小和块数total_reserved+二perm_gen_spec->max_size();if(totdljrcscrvcdmax_sizc()){vm_exit_during_initialization(overflowjnsg);}"""n_covered_regions+二permgen_spec->n_covered_regions();⑵•加上永久代的misc_data和misc_code的空间大小(数据区和代码区),但其实并不是堆的一部分size_ts=perm_gen_spec->misc_data_size()+perm_gen_spec->misc_code_size();total_reserved+二s;(3)•如果配置了UseLargePages,那么将向上将屮请的内存空间大小对齐至页if(UseLargePages){assert(total_reserved!=0,^totalreservedcannotbe0〃);totalreserved=roundto(totalreserved,os::large_page_size());if(total_reserved=extrabase,〃justchecking");//Re-reservetheregionatthealignedbaseaddress.os::release_memory(extra_base,extra_size);base二os::rcscrve_mcmory(size,base);}while(base==NULL);最后,在地址空间均已分配完毕,GenCollectedHeap的initialize()中为各代划分了各自的内存空间范围,就会调用各代的GenerationSpec的init()函数完成各代的初始化。switch(name())casePermGen::MarkSweepCompact:returnnewCompactingPermGen(perm_rs,sharedrs,init_size,remset,this);ttifndcfSERIALGCcasePermGen::MarkSweep:guarantee(false,"NYI");returnNULL;casePcrmGcn::ConcurrcntMarkSwccp:{assert(UseConcMarkSweepGC,z,UseConcMarkSweepGCshouldbeset〃);CardTableRS*ctrs=remset->as_CardTableRS();if(ctrs二二MULL){vmexit_during_initialization(〃RemSet/generationincompatibility.“);}//XXXPERMreturnnewCMSPermGen(permrs,init_size,ctrs, (FrccBlockDictionary::DictionaryChoicc)CMSDictionaryChoicc);}#endif//SERIALGCdefault:guarantee(false,"unrecognisedGenerationName77);returnNULL;各分代实现类的类关系如下: Generation归纳堆初始化的流程图如下:

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
大家都在看
近期热门
关闭