当前位置: 首页 > news >正文

怎样把自己做的网站上传做软装平台网站

怎样把自己做的网站上传,做软装平台网站,蛋糕网站模板,网站建设服务协议模板目录 写在前面#xff1a; 源码剖析#xff1a; Java层面#xff1a; JVM层面#xff1a; 使用危险点#xff1a; 总结#xff1a; 版本信息#xff1a; jdk版本#xff1a;jdk8u40 垃圾回收器#xff1a;Serial new/old 写在前面#xff1a; 不同的垃圾回收…目录 写在前面 源码剖析 Java层面 JVM层面 使用危险点 总结 版本信息 jdk版本jdk8u40 垃圾回收器Serial new/old 写在前面 不同的垃圾回收器所对应的算法不一样效率更不一样。在JDK8中默认为ParallelScavenge new/old。而笔者写文时使用Serial new/old两者算法一致只不过ParallelScavenge new/old发挥了多线程的优势所以在算法细节上大同小异。 对于大大大大大大部分Java业务场景来说都是强引用基本上不会使用到软、弱、虚引用。而在JDK1.2推出的软、弱、虚引用大部分出现场景都是在缓存中在JDK类库ThreadLocal、WeakHashMap。框架Mybatis、Netty、以及各种缓存框架等等。至于为什么要用在缓存中呢也很好理解因为这些引用实际上可有可无完美契合于缓存在有的时候给系统加速在系统内存紧张的时候清除缓存给核心业务使用。 源码剖析 这篇文章的篇幅会比较长也不容易理解。因为对于软、弱、虚引用处理细节体现在Java层面和JVM层面恰好JVM层面又与GC垃圾回收细节强关联所以笔者只能竭尽所能 Java层面 在Java层面就不得不补充一些前置知识以及Java层面如何处理这些引用。 软、弱、虚引用的基本表示 上图是软、弱、虚引用最基本的表示这里需要区分2个不同的对象一个是软、弱、虚对象一个是软、弱、虚引用的对象。 软、弱、虚对象 软、弱、虚引用的对象 所以下文需要介绍软、弱、虚对象的回收机制和区分具体的使用场景相信大家八股文多多少少背过这里跟八股文会有一点点出入 软当系统资源紧张但是又没那么那么紧张的时候根据最近最少使用回收软引用LRU算法当系统资源非常非常紧张的时候直接全部回收。可以携带引用对象也可以使用ReferenceQueue去处理伴随对象 弱只要发生GC就会回收。可以携带引用对象也可以使用ReferenceQueue去处理伴随对象 虚只要发生GC就会回收。不能携带引用对象。只能使用ReferenceQueue去处理伴随对象 上文有介绍软、弱、虚对象的回收机制这里有提到ReferenceQueue队列所以下文开始介绍Java层面如何使用ReferenceQueue做回收。 // java.lang.ref.Reference类中静态方法 static {// 创建一个ReferenceHandler线程。Thread handler new ReferenceHandler(tg, Reference Handler);handler.setPriority(Thread.MAX_PRIORITY); handler.setDaemon(true); handler.start(); } 在java.lang.ref.Reference类中静态方法中创建了一个ReferenceHandler线程。所以接下来看线程的执行体。 public void run() {while (true) {tryHandlePending(true);} }static boolean tryHandlePending(boolean waitForNotify) {ReferenceObject r;…………synchronized (lock) {if (pending ! null) {// 如果pedding不为null那么就代表GC回收到了软、弱、虚引用r pending;pending r.discovered;r.discovered null;} else {if (waitForNotify) {// 当还没产生pending链表的时候也即没有触发GC回收软、弱、虚引用// 当前线程直接去阻塞等待被JVM唤醒。lock.wait();}return waitForNotify;}}…………// 把GC回收到了软、弱、虚引用放入到对应的ReferenceQueue中。// 等待业务自己去处理ReferenceQueue队列。ReferenceQueue? super Object q r.queue;if (q ! ReferenceQueue.NULL) q.enqueue(r);return true; }boolean enqueue(Reference? extends T r) { synchronized (lock) {ReferenceQueue? queue r.queue;if ((queue NULL) || (queue ENQUEUED)) {return false;}// 头插法r.queue ENQUEUED;r.next (head null) ? r : head;head r;queueLength;lock.notifyAll();return true;} }判断当前pedding 是否为空如果为空代表当前GC没有触发回收软、弱、虚引用如果不为空代表当前GC回收软、弱、虚引用并且放入到pedding中把pedding的值放入到ReferenceQueue队列中业务维护的ReferenceQueue队列从队列中poll值去做对应的处理。 所以ReferenceQueue队列是业务层面自己维护传入到Reference中GC回收软、弱、虚引用后会把当前Reference放入到ReferenceQueue队列中。业务层面再通过poll取到Reference做对应的处理可以是处理伴随对象 下面是WeakHashMap对ReferenceQueue的使用。 WeakHashMap的使用 至此Java层面的处理已经看完接下来我们需要明白JVM是如何GC处理软、弱、虚引用并且放入到pedding中这样就全部闭环 JVM层面 具体的GC回收过程本文肯定是忽略当作黑盒即可 /hotspot/src/share/vm/memory/genCollectedHeap.cpp 文件中 // /hotspot/src/share/vm/memory/genCollectedHeap.cpp // 这里是GC垃圾回收的过程 void GenCollectedHeap::do_collection(bool full,bool clear_all_soft_refs,size_t size,bool is_tlab,int max_level) {…………// 是否需要清理所有的软引用const bool do_clear_all_soft_refs clear_all_soft_refs ||collector_policy()-should_clear_all_soft_refs();{…………for (int i starting_level; i max_level; i) {if (_gens[i]-should_collect(full, size, is_tlab)) {{// 从这里可以看出不同带都有一个引用的处理器。ReferenceProcessor* rp _gens[i]-ref_processor();rp-enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);// 改变回收策略rp-setup_policy(do_clear_all_soft_refs); // 不同代进行垃圾回收。_gens[i]-collect(full, do_clear_all_soft_refs, size, is_tlab);// gc回收后把回收的软、弱、虚引用赋值给pedding交给Java层面处理// 这里也对应到上下文了。if (!rp-enqueuing_is_done()) {rp-enqueue_discovered_references();} else { rp-set_enqueuing_is_done(false);}}}}…………} } 这里根据策略决定是否要清理所有的软引用一般是内存资源极度不够的时候才会新生代或者老年代的垃圾回收器进行垃圾回收这也对应了YGC和FullGC在GC回收后把回收到的软、弱、虚引用赋值给pedding交给Java层面处理 所以接下来需要看到老年代的垃圾回收器进行垃圾回收的时候如何处理的软、弱、虚引用。 /hotspot/src/share/vm/memory/defNewGeneration.cpp 文件中 // 新生代的垃圾回收 void DefNewGeneration::collect(bool full,bool clear_all_soft_refs,size_t size,bool is_tlab) {…………// 用于扫描软、弱、虚引用是否存活。ScanWeakRefClosure scan_weak_ref(this);// 对象扫描器用于GC root的复制FastScanClosure fsc_with_no_gc_barrier(this, false);FastScanClosure fsc_with_gc_barrier(this, true);// Klass的GC root扫描。KlassScanClosure klass_scan_closure(fsc_with_no_gc_barrier,gch-rem_set()-klass_rem_set());// GC Root广度搜索的扫描器// 也就是找到GC Root的引用作为下一批GC Root直到找完所有的存活对象。FastEvacuateFollowersClosure evacuate_followers(gch, _level, this,fsc_with_no_gc_barrier,fsc_with_gc_barrier);// 寻找根GC Root。// 因为是新生代的算法所以这里会把根GC Root复制到to区或者是老年代。gch-gen_process_strong_roots(_level,true, // Process younger gens, if any,// as strong roots.true, // activate StrongRootsScopetrue, // is scavengingSharedHeap::ScanningOption(so),fsc_with_no_gc_barrier,true, // walk *all* scavengable nmethodsfsc_with_gc_barrier,klass_scan_closure);// 根据GC Root找出GC Root所有的引用// 因为这里是处理引用所以这里会处理软、弱、虚等等引用。evacuate_followers.do_void();// 用于处理引用对象的存活。FastKeepAliveClosure keep_alive(this, scan_weak_ref);ReferenceProcessor* rp ref_processor();// 根据clear_all_soft_refs这个bool字段决定是否清理全部的软引用。rp-setup_policy(clear_all_soft_refs);// 具体的处理细节。const ReferenceProcessorStats stats rp-process_discovered_references(is_alive, keep_alive, evacuate_followers,NULL, _gc_timer);………… } 以上是YGC时新生代的回收不管是Full GC还是YGC都会对软、弱、虚引用做处理所以挑选YGC来做分析因为YGC简单一些但是对于软、弱、虚引用做处理都是一样的 由于处理软、弱、虚引用一定会和GC回收细节强关联所以很多是GC回收的细节代码笔者有吧注释给上并且当作黑盒就好。 创建好各种GC回收所需要扫描器这些扫描器最终都有一个共同的任务就是把存活对象复制到to区或者老年代GC Root的扫描根据已有的GC Root做广度遍历找出GC Root引用的对象作为下一批GC Root继续找引用直到遍历完整个堆软、弱、虚引的处理这也是接下来的重点 经过GC Root全部查找后Java堆的对象排布可能是这样 注意这里的软、弱、虚对象和软、弱、虚对象所引用对象是有区别的复制算法只会把软、弱、虚对象做复制软、弱、虚对象引用的对象要后续再做处理。 在看ReferenceProcessor类process_discovered_references方法之前需要介绍一下ReferenceProcessor类。 /hotspot/src/share/vm/memory/referenceProcessor.hpp 文件中 class ReferenceProcessor : public CHeapObjmtGC {protected:static ReferencePolicy* _default_soft_ref_policy;static ReferencePolicy* _always_clear_soft_ref_policy;ReferencePolicy* _current_soft_ref_policy;uint _num_q; uint _max_num_q; // 作为基地址。DiscoveredList* _discovered_refs; DiscoveredList* _discoveredSoftRefs; // 基于基地址的第一部分DiscoveredList* _discoveredWeakRefs; // 基于基地址的第二部分DiscoveredList* _discoveredFinalRefs; // 基于基地址的第三部分DiscoveredList* _discoveredPhantomRefs; // 基于基地址的第四部分 } 可以很清楚的看到这里有策略对象和几个DiscoveredList链表。链表中是保存了被处理的软、弱、虚的Java对象。并且在遍历完所有的GC Root后这里会把软、弱、虚的Java对象行程如下的链表。 所以接下来看到process_discovered_references方法具体处理细节。 /hotspot/src/share/vm/memory/referenceProcessor.cpp 文件中 ReferenceProcessorStats ReferenceProcessor::process_discovered_references(BoolObjectClosure* is_alive,OopClosure* keep_alive,VoidClosure* complete_gc,AbstractRefProcTaskExecutor* task_executor,GCTimer* gc_timer) {_soft_ref_timestamp_clock java_lang_ref_SoftReference::clock();// 软引用的处理size_t soft_count 0;{GCTraceTime tt(SoftReference, trace_time, false, gc_timer);soft_count process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,is_alive, keep_alive, complete_gc, task_executor);}// 修改时间戳。// 时间戳用于LRU算法寻找最近最少使用的软引用。update_soft_ref_master_clock();// 弱引用的处理size_t weak_count 0;{GCTraceTime tt(WeakReference, trace_time, false, gc_timer);weak_count process_discovered_reflist(_discoveredWeakRefs, NULL, true,is_alive, keep_alive, complete_gc, task_executor);}// 最终引用处理这个一般是用于收尾工作size_t final_count 0;{GCTraceTime tt(FinalReference, trace_time, false, gc_timer);final_count process_discovered_reflist(_discoveredFinalRefs, NULL, false,is_alive, keep_alive, complete_gc, task_executor);}// 虚引用处理size_t phantom_count 0;{GCTraceTime tt(PhantomReference, trace_time, false, gc_timer);phantom_count process_discovered_reflist(_discoveredPhantomRefs, NULL, false,is_alive, keep_alive, complete_gc, task_executor);}return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count); } 可以看到不管是软、弱、虚引用的处理都是调用process_discovered_reflist方法。 /hotspot/src/share/vm/memory/referenceProcessor.cpp 文件中 size_t ReferenceProcessor::process_discovered_reflist(DiscoveredList refs_lists[],ReferencePolicy* policy,bool clear_referent,BoolObjectClosure* is_alive,OopClosure* keep_alive,VoidClosure* complete_gc,AbstractRefProcTaskExecutor* task_executor) {// 根据策略决定是否能处理引用。// 策略只有软引用才有。// 弱、虚引用是不配有策略的弱、虚引用只要发生GC久回收if (policy ! NULL) {for (uint i 0; i _max_num_q; i) {process_phase1(refs_lists[i], policy,is_alive, keep_alive, complete_gc);}} // 遍历剩下的队列继续做过滤操作// 这个过滤是判断软、弱、虚对象引用的对象是否还活着如果活着那就不能处理这个引用。for (uint i 0; i _max_num_q; i) {process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);}// 根据clear_referent变量决定最终是否处理引用。for (uint i 0; i _max_num_q; i) {process_phase3(refs_lists[i], clear_referent,is_alive, keep_alive, complete_gc);}return total_list_count; } 软引用才有策略根据策略决定是否回收对象如果策略不让回收的对象那么就需要从DiscoveredList链表中remove并且保持存活直到下次GC 再尝试回收经过策略的决策后活下来的对象继续做过滤这次过滤是判断软、弱、虚对象引用的对象是否还活着如果活着那就不能处理这个引用所以用不好随时可能内存泄漏如果引用对象是存活的那么就需要从DiscoveredList链表中remove并且保持存活直到下次GC 再尝试回收经过第二步的过滤活下来的对象还要根据clear_referent变量决定最终是否处理引用对象。这一步只有虚引用才不能处理引用因为虚对象不能引用对象如果clear_reference为false那么就需要从DiscoveredList链表中remove并且保持存活直到下次GC 再尝试回收但是虚引用为false也没关系因为他指向本来就是null。 所以接下来可以看一下软引用的策略处理。 这里就比较简单了要不永远回收、要不永远不回收要不根据LRU算法得到最近最少使用的软引用优先回收没用的 所以在本文最上面写到软引用在内存紧张的时候但是不是非常紧张的时候会回收最少使用的根据LRU算法在内存非常非常紧张的时候策略直接是AlwaysCLearPolicy策略了就回收所有软引用 当经过层层过滤后最终存活的软、弱、虚对象就存在不同DiscoveredList链表中。我们在Java层面是从pedding获取到对象所以这边还需要把不同的DiscoveredList链表设置到pedding中。 所以接下来回到GenCollectedHeap::do_collection方法看到enqueue_discovered_references方法 /hotspot/src/share/vm/memory/referenceProcessor.cpp 文件中 bool ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) {return enqueue_discovered_ref_helperoop(this, task_executor); }template class T bool enqueue_discovered_ref_helper(ReferenceProcessor* ref,AbstractRefProcTaskExecutor* task_executor) {// 拿到Reference类中的pedding变量的地址因为pending是一个静态变量所以从mirror拿。T* pending_list_addr (T*)java_lang_ref_Reference::pending_list_addr();// 把链表链到pedding上ref-enqueue_discovered_reflists((HeapWord*)pending_list_addr, task_executor);return old_pending_list_value ! *pending_list_addr; }void ReferenceProcessor::enqueue_discovered_reflists(HeapWord* pending_list_addr,AbstractRefProcTaskExecutor* task_executor) {// 串行化遍历4个链表。for (uint i 0; i _max_num_q * number_of_subclasses_of_ref(); i) {// 只需要把每个链表的头部链到pending就行了。enqueue_discovered_reflist(_discovered_refs[i], pending_list_addr);_discovered_refs[i].set_head(NULL);_discovered_refs[i].set_length(0);} } 这里就是把经过层层筛选的软、弱、虚链表中的对象链到Reference类中pedding字段上。最终交给Java层面的ReferenceHandler线程去处理。 使用危险点 上面我们把所有的处理细节都分析完了所以接下来回忆到一处细节点。 /hotspot/src/share/vm/memory/referenceProcessor.cpp 文件中process_discovered_reflist方法这个方法是做过滤处理在process_phase2这个方法做过滤的时候会判断软、弱、虚对象的引用对象是否存活如果存活的情况下是不能做回收的。所以这里很容易发生内存泄露看到如下的Java代码。 public class ReferenceTest {public static void main(String[] args) {WeakHashMapObject,User weakHashMap new WeakHashMap();Object o1 new Object();weakHashMap.put(o1,new User(lihayyds)); // 只要o1不释放这就是内存泄露。weakHashMap.put(1,new User(lihayyds)); // 1是JVM字符串常量池指向的所以这也是一个内存泄露byte[] bytes1 new byte[1024 * 1024 * 1024];byte[] bytes2 new byte[1024 * 1024 * 1024];byte[] bytes3 new byte[1024 * 1024 * 1024];byte[] bytes4 new byte[1024 * 1024 * 1024];byte[] bytes5 new byte[1024 * 1024 * 1024];// 手动Full GC。System.gc();// Reference Queue 处理后的大小因为在size里面会去处理System.out.println(Reference Queue 处理后的大小为weakHashMap.size());} }class User{String name;public User(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;} } 结果如上图所示发生GC后弱引用根本没有回收就是因为弱引用指向的对象被其他地方强引用导致于在做筛选的过程中被筛选出去了不能去回收它。那么如果外部的这个强引用不释放那么这个弱引用引用的对象和弱引用对象永远无法回收从而无法达到弱引用的优势变相地说这就是内存泄漏 那么下面改进一下Java代码。 public class ReferenceTest {public static void main(String[] args) {WeakHashMapObject,User weakHashMap new WeakHashMap();// 这里直接不让外部引用这个Object对象weakHashMap.put(new Object(),new User(lihayyds)); weakHashMap.put(new Object(),new User(lihayyds)); byte[] bytes1 new byte[1024 * 1024 * 1024];byte[] bytes2 new byte[1024 * 1024 * 1024];byte[] bytes3 new byte[1024 * 1024 * 1024];byte[] bytes4 new byte[1024 * 1024 * 1024];byte[] bytes5 new byte[1024 * 1024 * 1024];// 手动Full GC。System.gc();// Reference Queue 处理后的大小因为在size里面会去处理System.out.println(Reference Queue 处理后的大小为weakHashMap.size());} }class User{String name;public User(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;} } 如上图所示弱引用引用的对象不让外部有强引用后直接正常了发生GC就回收了 总结 因为流程特别大强关联GC回收部分所以笔者只能竭尽所能源码注释总结画图来尽量描述明白
http://www.yingshimen.cn/news/97331/

相关文章:

  • seo网站模版学校网站建设实训总结
  • 深圳网站开发报价成都企业网站优化
  • 媒体网站的品牌建设延安有哪些做网站的公司
  • 猎头公司注册条件杭州专业seo服务公司
  • wordpress建博客网站佛山从事网站建设
  • 深圳网站优化运营科技成果转化
  • 陕西网站建设价格建筑人才网招聘网官网
  • 北京电商网站建设哪家好广东企业网站制作
  • 网站流量带宽湛江正规网站制作方案
  • 南通网站定制方案电商网站开发数据库设计
  • 外贸网站建设工作计划广西建设厅证书查询
  • 做交友信息网站可行么找百度做的网站可以过户
  • 哪个网站可以做c 的项目百度网站优化方案
  • 上海建网站费用优帮云wordpress照片ppt
  • 手机网站开发成本wordpress自定义注册页面
  • 厦门找一家做网站的公司好个人网页设计与实现论文免费
  • 用dw做网站怎么做出下拉菜单门户网站建设专业
  • 网站备案号官网开平网页定制
  • 做装修的网站有哪些内容wordpress 301重定向
  • 桂林商品房做民宿在哪个网站登记好网站开发 公司
  • 建设银行信用卡网站查询做英语作业的网站
  • asp网站开发技术wordpress 中文seo
  • 企业网站设计建设微信小程序视频网站开发教程
  • 沧州网站建设优化网站建设规划要点详解
  • 没网站怎么做淘宝客高考评卷工作全面展开
  • 设计微信公众号的网站吗好的地产设计网站
  • 营销型网站是啥数据分析师就业前景
  • 专用车网站建设价格网站做加QQ群链接
  • 企业网站搜索引擎推广方法包括二维码网站建设
  • 足球队世界排名榜西安百度网站快速优化