精华内容
下载资源
问答
  • 主要作用和目的? 我百度了一下.是这么回答-->内存管理是 : 指软件运行时对计算机内存资源分配和使用技术。 作用是 : 为了高效,快速分配,并且在适当时候释放和回收内存资源。OC内存管理机制说到...

    什么是内存管理?其最主要作用和目的?

    我百度了一下.是这么回答的-->

    内存管理是 : 指软件运行时对计算机内存资源的分配和使用的技术。 作用是 : 为了高效的,快速的分配,并且在适当的时候释放和回收内存资源。

    OC内存管理机制

    说到OC的内存管理机制 不得不说引用计数

    什么是引用计数?以下是我查看的比较合理的答案-->
    引用计数是 : 最普遍的垃圾回收策略之一。每一个对象都会有一个额外的计数值来表示当前被引用的次数。有新的引用,这个值就会+1;结束引用,这个值会自动-1,直到计数值为0时,对象所指的内存块就会废弃掉被系统回收,从而达到释放内存的目的。

    OC的内存管理机制 我个人感觉有四个词可以解释,"生成","持有","释放","废除".

    在"iOS与OS X多线程和内存管理"这本书上看到的对OC内存管理的方式,一共四条
    1.自己生成的对象,自己所持有.
    2.非自己生成的对象,自己也能持有.
    3.不再需要自己持有的对象时释放掉.
    4.非自己持有的对象无法释放.
    大家经过自己一段时间的开发会发现.其实OC的内存管理方式就是这样.


    当然ARC中的内存管理都交给系统来做了 管理方式这篇文章写的比较好 https://www.jianshu.com/p/48665652e4e4 可以做参考 之后小弟也会自己写一篇关系ARC内存管理这一块的文章出来,把自己的见解说出来.
    该文章纯属自己看书期间有感而发,加上之前面试遇到过这几个问题,并没有能系统的说出这几个问题的答案的原因才写出来的,如果有小哥看到该篇文章,并发现哪里有问题,可以随时纠正,小弟在此谢过了!


    转载于:https://juejin.im/post/5a5df99cf265da3e303c7fc0

    展开全文
  • 它是一个时段优先计划系统,其主要对象是决定制造与采购净需求计划。它是由主生产计划推动运行,但反过来,它又是主生产计划具体化和实现主生产计划保证计划。    由于物料需求计划是把主生产计划排产...
  • MS SQ图书管理系统是典型信息管理系统(MIS),开发主要包括后台数据库建立和维护以及前端应用程序开发两个方面。对于前者要求建立起数据一致性和完整性强、数据安全性好库。而对于后者则要求应用程序功能...
  • 在Oracle数据库中为了更好的管理大容量数据,专门开发了一些对应对象数据类型。具体来说,有如下几种: 一是BLOB数据类型。它是用来存储可变长度二进制数据。由于存储是通用二进制数据,为此在...
  • 内存代管理器TenuredGeneration作为基于内存分代管理的内存堆管理器GenCollectedHeap默认的旧生代管理器,它对垃圾对象的回收算法要比年青代Gc要复杂的多,但主体思路就是:标记-清除-压缩.本文主要围绕内存代Gc时的...

    内存代管理器TenuredGeneration作为基于内存分代管理的内存堆管理器GenCollectedHeap默认的旧生代管理器,它对垃圾对象的回收算法要比年青代Gc要复杂的多,但其主体思路就是:标记-清除-压缩.本文主要围绕内存代Gc时的三个过程来详细讲解TenuredGeneration是如何进行垃圾回收的.

    一.Gc条件

         可对 TenuredGeneration管理的旧生代进行Gc的条件主要有4个,满足其中的任何一个即可对旧生代进行垃圾回收:

    1. 1.当前是Full Gc  
    2. 2.可在当前内存代分配请求的空间  
    3. 3.当前内存代空闲空间<10000  
    4. 4.当前内存代容量>上一次Gc之前的容量  
         具体代码可参见如下:
    1. bool TenuredGeneration::should_collect(bool  full, size_t size, bool   is_tlab) {  
    2.   // This should be one big conditional or (||), but I want to be able to tell  
    3.   // why it returns what it returns (without re-evaluating the conditionals  
    4.   // in case they aren't idempotent), so I'm doing it this way.  
    5.   // DeMorgan says it's okay.  
    6.   bool result = false;  
    7.   
    8.   if (!result && full) {  
    9.     result = true;  
    10.     if (PrintGC && Verbose) {  
    11.       gclog_or_tty->print_cr("TenuredGeneration::should_collect: because full");  
    12.     }  
    13.   }  
    14.   
    15.   if (!result && should_allocate(size, is_tlab)) {  
    16.     result = true;  
    17.     if (PrintGC && Verbose) {  
    18.       gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"  
    19.                     " should_allocate(" SIZE_FORMAT ")", size);  
    20.     }  
    21.   }  
    22.   
    23.   // If we don't have very much free space.  
    24.   // XXX: 10000 should be a percentage of the capacity!!!  
    25.   if (!result && free() < 10000) {  
    26.     result = true;  
    27.     if (PrintGC && Verbose) {  
    28.       gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"  
    29.                     " free(): " SIZE_FORMAT,  
    30.                     free());  
    31.     }  
    32.   }  
    33.   
    34.   // If we had to expand to accomodate promotions from younger generations  
    35.   if (!result && _capacity_at_prologue < capacity()) {  
    36.     result = true;  
    37.     if (PrintGC && Verbose) {  
    38.       gclog_or_tty->print_cr("TenuredGeneration::should_collect: because"  
    39.                     "_capacity_at_prologue: " SIZE_FORMAT " < capacity(): " SIZE_FORMAT,  
    40.                     _capacity_at_prologue, capacity());  
    41.     }  
    42.   }  
    43.   
    44.   return result;  
    45. }  

    二.Gc基本流程

           默认的旧生代管理器TenuredGeneration回收垃圾对象的基本思路就是:

    1. 第一步: 标记所有的active对象  
    2.   
    3. 第二步: 计算所有active对象在其内存代压缩后的偏移位置  
    4.   
    5. 第三步: 更新所有active对象的地址映射表  
    6.   
    7. 第四步: 移动复制所有的active对象到新的存储位置  

    1.标记所有的active对象

       TenuredGeneration标记所有active对象的过程跟年青代Gc相似,都是从根对象开始以深度优先的方式搜索标记所有的active对象,具体过程如下:

    1. /** 
    2.  * 从根对象开始递归迭代标记所有活动的对象 
    3.  */  
    4. void GenMarkSweep::mark_sweep_phase1(int level,  
    5.                                   bool clear_all_softrefs) {  
    6.   // Recursively traverse all live objects and mark them  
    7.   TraceTime tm("phase 1", PrintGC && Verbose, true, gclog_or_tty);  
    8.   trace(" 1");  
    9.   
    10.   VALIDATE_MARK_SWEEP_ONLY(reset_live_oop_tracking(false));  
    11.   
    12.   GenCollectedHeap* gch = GenCollectedHeap::heap();  
    13.   
    14.   // Because follow_root_closure is created statically, cannot  
    15.   // use OopsInGenClosure constructor which takes a generation,  
    16.   // as the Universe has not been created when the static constructors  
    17.   // are run.  
    18.   follow_root_closure.set_orig_generation(gch->get_gen(level));  
    19.   
    20.   /** 
    21.    * 遍历当前所有的根对象并标记,并递归遍历标记它们的引用对象 
    22.    */  
    23.   gch->gen_process_strong_roots(level,  
    24.                                 false// Younger gens are not roots.  
    25.                                 true,  // activate StrongRootsScope  
    26.                                 true,  // Collecting permanent generation.  
    27.                                 SharedHeap::SO_SystemClasses,  
    28.                                 &follow_root_closure,  
    29.                                 true,   // walk code active on stacks  
    30.                                 &follow_root_closure);  
    31.   
    32.   //标记所有的软引用对象  
    33.   {  
    34.     ref_processor()->setup_policy(clear_all_softrefs);  
    35.     ref_processor()->process_discovered_references(&is_alive, &keep_alive, &follow_stack_closure, NULL);  
    36.   }  
    37.   
    38.   // Follow system dictionary roots and unload classes  
    39.   bool purged_class = SystemDictionary::do_unloading(&is_alive);  
    40.   
    41.   // 清理代码高速缓冲区  
    42.   CodeCache::do_unloading(&is_alive, &keep_alive, purged_class);  
    43.   follow_stack(); // Flush marking stack  
    44.   
    45.   // Update subklass/sibling/implementor links of live klasses  
    46.   follow_weak_klass_links();  
    47.   assert(_marking_stack.is_empty(), "just drained");  
    48.   
    49.   //清理未被标记的软/弱引用对象  
    50.   follow_mdo_weak_refs();  
    51.   assert(_marking_stack.is_empty(), "just drained");  
    52.   
    53.   //清除没有被引用的常量字符串  
    54.   StringTable::unlink(&is_alive);  
    55.   
    56.   //清除符号表中没有被引用的符号  
    57.   SymbolTable::unlink();  
    58.   
    59.   assert(_marking_stack.is_empty(), "stack should be empty by now");  
    60. }  

    2.计算所有active对象在其内存代压缩后的偏移位置

        以内存代为单位计算各内存代中的active对象压缩后的新存储位置:

    1. /** 
    2.  * 通过对象的标记,计算存活的对象在其内存区压缩后的偏移位置 
    3.  */  
    4. void GenMarkSweep::mark_sweep_phase2() {  
    5.   // Now all live objects are marked, compute the new object addresses.  
    6.   
    7.   // It is imperative that we traverse perm_gen LAST. If dead space is  
    8.   // allowed a range of dead object may get overwritten by a dead int  
    9.   // array. If perm_gen is not traversed last a klassOop may get  
    10.   // overwritten. This is fine since it is dead, but if the class has dead  
    11.   // instances we have to skip them, and in order to find their size we  
    12.   // need the klassOop!  
    13.   //  
    14.   // It is not required that we traverse spaces in the same order in  
    15.   // phase2, phase3 and phase4, but the ValidateMarkSweep live oops  
    16.   // tracking expects us to do so. See comment under phase4.  
    17.   
    18.   GenCollectedHeap* gch = GenCollectedHeap::heap();  
    19.   Generation* pg = gch->perm_gen();  
    20.   
    21.   TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty);  
    22.   trace("2");  
    23.   
    24.   VALIDATE_MARK_SWEEP_ONLY(reset_live_oop_tracking(false));  
    25.   
    26.   //计算年青代+老生代中active对象在其内存代压缩后的偏移位置  
    27.   gch->prepare_for_compaction();  
    28.   
    29.   VALIDATE_MARK_SWEEP_ONLY(_live_oops_index_at_perm = _live_oops_index);  
    30.   
    31.   //计算永久代中active对象在其内存代压缩后的偏移位置  
    32.   CompactPoint perm_cp(pg, NULL, NULL);  
    33.   pg->prepare_for_compaction(&perm_cp);  
    34.   
    35. }  
       在内存代内部,又是以内存区为单位来计算的:
    1. /** 
    2.  * 计算内存代放入各个内存区中活着的对象在其压缩后的偏移位置 
    3.  */  
    4. void Generation::prepare_for_compaction(CompactPoint* cp) {  
    5.   // Generic implementation, can be specialized  
    6.   CompactibleSpace* space = first_compaction_space();  
    7.   while (space != NULL) {  
    8.     space->prepare_for_compaction(cp);  
    9.     space = space->next_compaction_space();  
    10.   }  
    11. }  
        内存区的计算方法是(对象新的存储地址存放在对象实例的_makr属性中):
    1. /** 
    2.  * 计算内存区中所有活着(被标记)的对象在其被压缩后的偏移位置 
    3.  */  
    4. void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) {  
    5.   SCAN_AND_FORWARD(cp, end, block_is_obj, block_size);  
    6. }  
    7.   
    8. #define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) {            \  
    9.   /* Compute the new addresses for the live objects and store it in the mark \ 
    10.    * Used by universe::mark_sweep_phase2()                                   \ 
    11.    */                                                                        \  
    12.   HeapWord* compact_top; /* This is where we are currently compacting to. */ \  
    13.                                                                              \  
    14.   /* We're sure to be here before any objects are compacted into this        \ 
    15.    * space, so this is a good time to initialize this:                       \ 
    16.    */                                                                        \  
    17.   set_compaction_top(bottom());                                              \  
    18.                                                                              \  
    19.   if (cp->space == NULL) {                                                   \  
    20.     assert(cp->gen != NULL, "need a generation");                            \  
    21.     assert(cp->threshold == NULL, "just checking");                          \  
    22.     assert(cp->gen->first_compaction_space() == this"just checking");      \  
    23.                                                                              \  
    24.     cp->space = cp->gen->first_compaction_space();                           \  
    25.     compact_top = cp->space->bottom();                                       \  
    26.     cp->space->set_compaction_top(compact_top);                              \  
    27.     cp->threshold = cp->space->initialize_threshold();                       \  
    28.   } else {                                                                   \  
    29.     compact_top = cp->space->compaction_top();                               \  
    30.   }                                                                          \  
    31.                                                                              \  
    32.   /* We allow some amount of garbage towards the bottom of the space, so     \ 
    33.    * we don't start compacting before there is a significant gain to be made.\ 
    34.    * Occasionally, we want to ensure a full compaction, which is determined  \ 
    35.    * by the MarkSweepAlwaysCompactCount parameter.                           \ 
    36.    */                                                                        \  
    37.   int invocations = SharedHeap::heap()->perm_gen()->stat_record()->invocations;\  
    38.   bool skip_dead = (MarkSweepAlwaysCompactCount < 1)                         \  
    39.     ||((invocations % MarkSweepAlwaysCompactCount) != 0);                    \  
    40.                                                                              \  
    41.   size_t allowed_deadspace = 0;                                              \  
    42.   if (skip_dead) {                                                           \  
    43.     const size_t ratio = allowed_dead_ratio();                               \  
    44.     allowed_deadspace = (capacity() * ratio / 100) / HeapWordSize;           \  
    45.   }                                                                          \  
    46.                                                                              \  
    47.   /**                                                                        \ 
    48.    * 当前内存区压缩的开始位置和结束位置                                                                                                                                                   \ 
    49.    */                                                                        \  
    50.   HeapWord* q = bottom();                                                    \  
    51.   HeapWord* t = scan_limit();                                                \  
    52.                                                                              \  
    53.   HeapWord*  end_of_live= q;    /* One byte beyond the last byte of the last \ 
    54.                                    live object. */                           \  
    55.   HeapWord*  first_dead = end();/* The first dead object. */                 \  
    56.   LiveRange* liveRange  = NULL; /* The current live range, recorded in the   \ 
    57.                                    first header of preceding free area. */   \  
    58.   _first_dead = first_dead;   /*当前内存区中最后一个active对象*/                 \  
    59.                                                                              \  
    60.   const intx interval = PrefetchScanIntervalInBytes;                         \  
    61.                                                                              \  
    62.    /**                                                                       \ 
    63.     * 开始遍历该内存区分配的所有对象                                                                                                                                                        \ 
    64.     */                                                                       \  
    65.   while (q < t) {                                                            \  
    66.     assert(!block_is_obj(q) ||                                               \  
    67.            oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() ||   \  
    68.            oop(q)->mark()->has_bias_pattern(),                               \  
    69.            "these are the only valid states during a mark sweep");           \  
    70.     /**                                                                      \ 
    71.      * active对象,则确定其新的存储位置                                           \ 
    72.      */                                                                      \  
    73.     if (block_is_obj(q) && oop(q)->is_gc_marked()) {                         \  
    74.       /* prefetch beyond q */                                                \  
    75.       Prefetch::write(q, interval);                                          \  
    76.       /* size_t size = oop(q)->size();  changing this for cms for perm gen */\  
    77.       /*对象大小*/                                                            \  
    78.       size_t size = block_size(q);                                           \  
    79.       compact_top = cp->space->forward(oop(q), size, cp, compact_top);       \  
    80.       q += size;                                                             \  
    81.       end_of_live = q;                                                       \  
    82.     } else {                                                                 \  
    83.       /* 垃圾对象,则一直遍历到其下一个active对象 */                                \  
    84.       HeapWord* end = q;                                                     \  
    85.       do {                                                                   \  
    86.         /* prefetch beyond end */                                            \  
    87.         Prefetch::write(end, interval);                                      \  
    88.         end += block_size(end);                                              \  
    89.       } while (end < t && (!block_is_obj(end) || !oop(end)->is_gc_marked()));\  
    90.                                                                              \  
    91.       /* see if we might want to pretend this object is alive so that        \ 
    92.        * we don't have to compact quite as often.                            \ 
    93.        */                                                                    \  
    94.       if (allowed_deadspace > 0 && q == compact_top) {                       \  
    95.         size_t sz = pointer_delta(end, q);                                   \  
    96.         if (insert_deadspace(allowed_deadspace, q, sz)) {                    \  
    97.           compact_top = cp->space->forward(oop(q), sz, cp, compact_top);     \  
    98.           q = end;                                                           \  
    99.           end_of_live = end;                                                 \  
    100.           continue;                                                          \  
    101.         }                                                                    \  
    102.       }                                                                      \  
    103.                                                                              \  
    104.       /* otherwise, it really is a free region. */                           \  
    105.                                                                              \  
    106.       /* for the previous LiveRange, record the end of the live objects. */  \  
    107.       if (liveRange) {                                                       \  
    108.         liveRange->set_end(q);                                               \  
    109.       }                                                                      \  
    110.                                                                              \  
    111.       /* record the current LiveRange object.                                \ 
    112.        * liveRange->start() is overlaid on the mark word.                    \ 
    113.        */                                                                    \  
    114.       liveRange = (LiveRange*)q;                                             \  
    115.       liveRange->set_start(end);                                             \  
    116.       liveRange->set_end(end);                                               \  
    117.                                                                              \  
    118.       /* see if this is the first dead region. */                            \  
    119.       if (q < first_dead) {                                                  \  
    120.         first_dead = q;                                                      \  
    121.       }                                                                      \  
    122.                                                                              \  
    123.       /* move on to the next object */                                       \  
    124.       q = end;                                                               \  
    125.     }                                                                        \  
    126.   }                                                                          \  
    127.                                                                              \  
    128.   assert(q == t, "just checking");                                           \  
    129.   if (liveRange != NULL) {                                                   \  
    130.     liveRange->set_end(q);                                                   \  
    131.   }                                                                          \  
    132.   _end_of_live = end_of_live;                                                \  
    133.   if (end_of_live < first_dead) {                                            \  
    134.     first_dead = end_of_live;                                                \  
    135.   }                                                                          \  
    136.   _first_dead = first_dead;                                                  \  
    137.                                                                              \  
    138.   /* save the compaction_top of the compaction space. */                     \  
    139.   cp->space->set_compaction_top(compact_top);                                \  
    140. }  

    3.更新所有active对象的地址映射表

       该过程的实现和标记所有的active对象很相似,就是一个是标记,一个是更新地址指针:

    1. /** 
    2.  * 从根对象开始递归迭代更新所有活动对象的地址映射表(调整所有的对象指针) 
    3.  */  
    4. void GenMarkSweep::mark_sweep_phase3(int level) {  
    5.   GenCollectedHeap* gch = GenCollectedHeap::heap();  
    6.   Generation* pg = gch->perm_gen();  
    7.   
    8.   // Adjust the pointers to reflect the new locations  
    9.   TraceTime tm("phase 3", PrintGC && Verbose, true, gclog_or_tty);  
    10.   trace("3");  
    11.   
    12.   VALIDATE_MARK_SWEEP_ONLY(reset_live_oop_tracking(false));  
    13.   
    14.   // Needs to be done before the system dictionary is adjusted.  
    15.   pg->pre_adjust_pointers();  
    16.   
    17.   // Because the two closures below are created statically, cannot  
    18.   // use OopsInGenClosure constructor which takes a generation,  
    19.   // as the Universe has not been created when the static constructors  
    20.   // are run.  
    21.   adjust_root_pointer_closure.set_orig_generation(gch->get_gen(level));  
    22.   adjust_pointer_closure.set_orig_generation(gch->get_gen(level));  
    23.   
    24.   gch->gen_process_strong_roots(level,  
    25.                                 false// Younger gens are not roots.  
    26.                                 true,  // activate StrongRootsScope  
    27.                                 true,  // Collecting permanent generation.  
    28.                                 SharedHeap::SO_AllClasses,  
    29.                                 &adjust_root_pointer_closure,  
    30.                                 false// do not walk code  
    31.                                 &adjust_root_pointer_closure);  
    32.   
    33.   // Now adjust pointers in remaining weak roots.  (All of which should  
    34.   // have been cleared if they pointed to non-surviving objects.)  
    35.   CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure,  
    36.                                                    /*do_marking=*/ false);  
    37.   gch->gen_process_weak_roots(&adjust_root_pointer_closure,  
    38.                               &adjust_code_pointer_closure,  
    39.                               &adjust_pointer_closure);  
    40.   
    41.   adjust_marks();  
    42.   GenAdjustPointersClosure blk;  
    43.   gch->generation_iterate(&blk, true);  
    44.   pg->adjust_pointers();  
    45. }  
       这里的对象地址映射表实际上就是前面的博文内存堆Gc时公认的根对象 中提到的实例对象句柄.
    1. /** 
    2.  * 调整对象的物理地址指针 
    3.  */  
    4. template <class T> inline void MarkSweep::adjust_pointer(T* p, bool isroot) {  
    5.   T heap_oop = oopDesc::load_heap_oop(p);  
    6.   
    7.   if (!oopDesc::is_null(heap_oop)) {  
    8.     oop obj     = oopDesc::decode_heap_oop_not_null(heap_oop);  
    9.     oop new_obj = oop(obj->mark()->decode_pointer()); //对象新的地址指针  
    10.     assert(new_obj != NULL ||                         // is forwarding ptr?  
    11.            obj->mark() == markOopDesc::prototype() || // not gc marked?  
    12.            (UseBiasedLocking && obj->mark()->has_bias_pattern()) ||  
    13.                                                       // not gc marked?  
    14.            obj->is_shared(),                          // never forwarded?  
    15.            "should be forwarded");  
    16.   
    17.     if (new_obj != NULL) {  
    18.       assert(Universe::heap()->is_in_reserved(new_obj),  
    19.              "should be in object space");  
    20.   
    21.       //更新对象的物理地址指针  
    22.       oopDesc::encode_store_heap_oop_not_null(p, new_obj);  
    23.     }  
    24.   }  
    25.   
    26.   VALIDATE_MARK_SWEEP_ONLY(track_adjusted_pointer(p, isroot));  
    27. }  

    4.移动复制所有的active对象到新的存储位置

        该过程跟计算所有active对象在其内存代压缩后的偏移位置的操作流程很相似,这里不在详细赘述.

    三.Gc后的内存代大小调整

           内存堆管理器在对某些内存代进行Gc之后,基本都会调整他们的内存容量,即对内存代进行扩容还是缩容.这个操作主要受控于两个参数:最小空闲率(MinHeapFreeRatio)和最大空闲率MaxHeapFreeRatio.TenuredGeneration根据这两个参数来调整旧生代的容量过程如下:

    1. /** 
    2.  * 调整当前内存代的容量(一般发生在一次Gc之后) 
    3.  */  
    4. void TenuredGeneration::compute_new_size() {  
    5.   assert(_shrink_factor <= 100, "invalid shrink factor");  
    6.   size_t current_shrink_factor = _shrink_factor;  
    7.   _shrink_factor = 0;  
    8.   
    9.   printf("%s[%d] [tid: %lu]: 当前内存代[%s]开始调整其容量大小.\n", __FILE__, __LINE__, pthread_self(), this->name());  
    10.   
    11.   // We don't have floating point command-line arguments  
    12.   // Note:  argument processing ensures that MinHeapFreeRatio < 100.  
    13.   const double minimum_free_percentage = MinHeapFreeRatio / 100.0;  //内存代的最小空闲率  
    14.   const double maximum_used_percentage = 1.0 - minimum_free_percentage;  
    15.   
    16.   //一次Gc之后,当前内存代的使用量和容量  
    17.   const size_t used_after_gc = used();  
    18.   const size_t capacity_after_gc = capacity();  
    19.   
    20.   //计算当前内存代期望的最小容量  
    21.   const double min_tmp = used_after_gc / maximum_used_percentage;  
    22.   size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx));  
    23.   // Don't shrink less than the initial generation size  
    24.   minimum_desired_capacity = MAX2(minimum_desired_capacity, spec()->init_size());  
    25.   
    26.   assert(used_after_gc <= minimum_desired_capacity, "sanity check");  
    27.   
    28.   if (PrintGC && Verbose) {  
    29.     const size_t free_after_gc = free();  
    30.     const double free_percentage = ((double)free_after_gc) / capacity_after_gc;  
    31.     gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: ");  
    32.     gclog_or_tty->print_cr("  "  
    33.                   "  minimum_free_percentage: %6.2f"  
    34.                   "  maximum_used_percentage: %6.2f",  
    35.                   minimum_free_percentage,  
    36.                   maximum_used_percentage);  
    37.     gclog_or_tty->print_cr("  "  
    38.                   "   free_after_gc   : %6.1fK"  
    39.                   "   used_after_gc   : %6.1fK"  
    40.                   "   capacity_after_gc   : %6.1fK",  
    41.                   free_after_gc / (double) K,  
    42.                   used_after_gc / (double) K,  
    43.                   capacity_after_gc / (double) K);  
    44.     gclog_or_tty->print_cr("  "  
    45.                   "   free_percentage: %6.2f",  
    46.                   free_percentage);  
    47.   }  
    48.   
    49.   //当前内存代的实际容量小于期望的容量,则扩展当前内存代的容量  
    50.   if (capacity_after_gc < minimum_desired_capacity) {  
    51.     // If we have less free space than we want then expand  
    52.     size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;  
    53.   
    54.     // Don't expand unless it's significant  
    55.     if (expand_bytes >= _min_heap_delta_bytes) {  
    56.       printf("%s[%d] [tid: %lu]: Gc之后,试图为内存代[%s]的容量扩大 %lu bytes.\n", __FILE__, __LINE__, pthread_self(), this->name(), expand_bytes);  
    57.       expand(expand_bytes, 0); // safe if expansion fails  
    58.     }  
    59.   
    60.     if (PrintGC && Verbose) {  
    61.       gclog_or_tty->print_cr("    expanding:"  
    62.                     "  minimum_desired_capacity: %6.1fK"  
    63.                     "  expand_bytes: %6.1fK"  
    64.                     "  _min_heap_delta_bytes: %6.1fK",  
    65.                     minimum_desired_capacity / (double) K,  
    66.                     expand_bytes / (double) K,  
    67.                     _min_heap_delta_bytes / (double) K);  
    68.     }  
    69.   
    70.     return;  
    71.   }  
    72.   
    73.   // No expansion, now see if we want to shrink  
    74.   size_t shrink_bytes = 0;  
    75.   // We would never want to shrink more than this  
    76.   size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity;  
    77.   
    78.   if (MaxHeapFreeRatio < 100) {  
    79.     //计算当前内存代期望的大容量  
    80.     const double maximum_free_percentage = MaxHeapFreeRatio / 100.0;  
    81.     const double minimum_used_percentage = 1.0 - maximum_free_percentage;  
    82.     const double max_tmp = used_after_gc / minimum_used_percentage;  
    83.     size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));  
    84.     maximum_desired_capacity = MAX2(maximum_desired_capacity, spec()->init_size());  
    85.   
    86.     if (PrintGC && Verbose) {  
    87.       gclog_or_tty->print_cr("  "  
    88.                              "  maximum_free_percentage: %6.2f"  
    89.                              "  minimum_used_percentage: %6.2f",  
    90.                              maximum_free_percentage,  
    91.                              minimum_used_percentage);  
    92.       gclog_or_tty->print_cr("  "  
    93.                              "  _capacity_at_prologue: %6.1fK"  
    94.                              "  minimum_desired_capacity: %6.1fK"  
    95.                              "  maximum_desired_capacity: %6.1fK",  
    96.                              _capacity_at_prologue / (double) K,  
    97.                              minimum_desired_capacity / (double) K,  
    98.                              maximum_desired_capacity / (double) K);  
    99.     }  
    100.     assert(minimum_desired_capacity <= maximum_desired_capacity,  
    101.            "sanity check");  
    102.   
    103.     //当前内存代Gc之后的容量大于期望的最大容量  
    104.     if (capacity_after_gc > maximum_desired_capacity) {  
    105.       // Capacity too large, compute shrinking size  
    106.       shrink_bytes = capacity_after_gc - maximum_desired_capacity;  
    107.       // We don't want shrink all the way back to initSize if people call  
    108.       // System.gc(), because some programs do that between "phases" and then  
    109.       // we'd just have to grow the heap up again for the next phase.  So we  
    110.       // damp the shrinking: 0% on the first call, 10% on the second call, 40%  
    111.       // on the third call, and 100% by the fourth call.  But if we recompute  
    112.       // size without shrinking, it goes back to 0%.  
    113.       shrink_bytes = shrink_bytes / 100 * current_shrink_factor;  
    114.       assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");  
    115.   
    116.       if (current_shrink_factor == 0) {  
    117.         _shrink_factor = 10;  
    118.       } else {  
    119.         _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100);  
    120.       }  
    121.   
    122.       if (PrintGC && Verbose) {  
    123.         gclog_or_tty->print_cr("  "  
    124.                       "  shrinking:"  
    125.                       "  initSize: %.1fK"  
    126.                       "  maximum_desired_capacity: %.1fK",  
    127.                       spec()->init_size() / (double) K,  
    128.                       maximum_desired_capacity / (double) K);  
    129.         gclog_or_tty->print_cr("  "  
    130.                       "  shrink_bytes: %.1fK"  
    131.                       "  current_shrink_factor: %d"  
    132.                       "  new shrink factor: %d"  
    133.                       "  _min_heap_delta_bytes: %.1fK",  
    134.                       shrink_bytes / (double) K,  
    135.                       current_shrink_factor,  
    136.                       _shrink_factor,  
    137.                       _min_heap_delta_bytes / (double) K);  
    138.       }  
    139.     }  
    140.   }  
    141.   
    142.   if (capacity_after_gc > _capacity_at_prologue) {  
    143.     //当前内存代Gc之后的容量大于Gc之前的容量,那么就是在内存代Gc时为了存储升级来的active对象而扩展了内存容量,  
    144.     //现在至少应该缩小到Gc之前的容量大小  
    145.     size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue;  
    146.     expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes);  
    147.     // We have two shrinking computations, take the largest  
    148.     shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion);  
    149.   
    150.     assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");  
    151.     if (PrintGC && Verbose) {  
    152.       gclog_or_tty->print_cr("  "  
    153.                              "  aggressive shrinking:"  
    154.                              "  _capacity_at_prologue: %.1fK"  
    155.                              "  capacity_after_gc: %.1fK"  
    156.                              "  expansion_for_promotion: %.1fK"  
    157.                              "  shrink_bytes: %.1fK",  
    158.                              capacity_after_gc / (double) K,  
    159.                              _capacity_at_prologue / (double) K,  
    160.                              expansion_for_promotion / (double) K,  
    161.                              shrink_bytes / (double) K);  
    162.     }  
    163.   }  
    164.   
    165.   // Don't shrink unless it's significant  
    166.   if (shrink_bytes >= _min_heap_delta_bytes) {  
    167.     printf("%s[%d] [tid: %lu]: Gc之后,试图为内存代[%s]的容量缩小 %lu bytes.\n", __FILE__, __LINE__, pthread_self(), this->name(), shrink_bytes);  
    168.     shrink(shrink_bytes);  
    169.   }  
    170.   
    171.   assert(used() == used_after_gc && used_after_gc <= capacity(),  
    172.          "sanity check");  
    173. }  

    展开全文
  • 具有可自定义文件存储的对象管理 Config文件支持+ Settings文件支持(Configs存储常规数据,Settings存储用户可控制设置) Json支持+基于接口支持以注入其他配置扩展 反射缓存+自动序列化/反序列化 一些即将...
  • C++中用对象管理资源的主要目的是为了利用C++的“自动调用析构函数”的机制来避免内存泄漏。 上一节中提到可以用智能指针或者计数型智能指针作为对象管理资源,这两个类指针对象包含了一个get成员函数用于返回...

    C++中用对象管理资源的主要目的是为了利用C++的“自动调用析构函数”的机制来避免内存泄漏。

    上一节中提到可以用智能指针或者计数型智能指针作为对象来管理资源,这两个类指针对象包含了一个get成员函数用于返回其内部的原始指向资源的指针,这是由对象到原始指针的显式转换,此外,它们还可以通过指针取值操作符(.和->)来实现隐式转换。

    通常,用对象管理资源时,都应在对象中包含获取原始指针的方法,这种方法可以是显式或是隐式的,显示的转换比较安全,隐式有可能会与预期的结果相遍悖,但用户用起来更方便,使用时需要根据情况具体处理。

     

    以上整理自Effective C++第三版case 15.

    转载于:https://www.cnblogs.com/sophia-yun/archive/2013/05/13/3076452.html

    展开全文
  • 1. 概述  本章内容包括 管理非托管资源、使用IDisposable接口 以及 管理析构器和垃圾回收。... 而堆空间,是由垃圾回收器管理的。  ③ 垃圾回收器的工作原理是:启动以后,垃圾回收器的标记程序会...

    1. 概述

      本章内容包括 管理非托管资源、使用IDisposable接口 以及 管理析构器和垃圾回收。

    2. 主要内容

      2.1 理解垃圾回收机制

        ① 代码执行的时候,内存中有两个地方存放数据项:堆 和 栈。

        ② 一个方法结束的时候,其使用的栈空间会被自动清空。 而堆空间,是由垃圾回收器管理的。

        ③ 垃圾回收器的工作原理是:启动以后,垃圾回收器的标记程序会遍历堆上保存的对象,标记出仍然被引用的对象,然后压缩程序启动,它会把当前仍然存在引用的对象移动到一起,然后释放掉其他不存在引用的对象。

        ④ 执行垃圾回收期间,为了确保对象状态的准确性,系统会暂停其他所有线程的执行,直到垃圾回收执行完毕。这可能会导致一定的程序响应问题。

        ⑤ 为了解决上述问题,垃圾回收器被设计成智能的。它会尽量在堆空间不足或内存不足的时候启动,而且尽量会在程序使用率低的时候启动。

        ⑥ 执行标记程序的时候,首次遍历到的对象默认是Generation 0,如果检测到该对象存在引用,则会提高该对象的Generation。其中根据的原则是:长时间停留的对象,可能会停留较长时间。所以这些对象仅会在空间不足的时候才会去检测和释放。

      2.2 管理非托管资源

        不涉及非托管资源的时候,基本无需考虑内存及资源管理问题,垃圾回收器都能处理好。但是一旦涉及到非托管资源,垃圾回收器就无能为力了,这时候就需要手动释放资源。

        析构器(finalizer)是释放资源的一种方式,但是C#中,析构器的执行时间是不确定的,是由垃圾回收器的算法决定的。但是可以通过调用GC.Collect来强制执行析构器。(这种做法是不推荐的)

    StreamWriter sw = File.CreateFile("temp.dat");
    sw.Write("some data");
    GC.Collect();
    GC.WaitForPendingFinalizers();
    File.Delete("temp.dat");

       析构器延长了对象的生命周期。因为析构器总要执行,.net平台会在一个特殊的析构队列中保存一个该对象的引用。这会推迟垃圾回收器的回收时间。

        综上所述,对于释放非托管资源,析构器不是一个很好的方案。.net有更好的推荐:IDisposable。

    using(StreamWriter stream = File.CreateText(“temp.dat”))
    {   stream.Write(“some data”);   stream.Dispose();   File.Delete(“temp.dat”);
    }

        使用using,可以自动处理其中代码的异常情况,避免因为代码中的异常可能导致的资源没有释放的问题。

      2.3 实现IDisposable接口和析构器

        在自定义类型中同时实现IDisposable接口和析构器,是一个必要的方案。可以避免用户忘记调用Dispose方法的情况。

    class UnmanagedWrapper : IDisposable
    {
        public FileStream Stream { get; private set;}
    
        public UnmananagedWrapper()
        {
            this.Stream = File.Open("temp.dat", FileMode.Create);
        }
    
        ~UnmanagedWrapper()
        {
            Dispose(false);
        }
    
        public void Close()
        {
            Dispose();
        }
    
        public void Dispose()
        {
            Dispose(true);
            System.GC.SuppressFinalizer(this);
        }
    
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (Stream != null)
                    Stream.Close();
            }
        }
    }        

        * System.GC.SuppressFinalizer(object obj)会请求系统不要调用指定对象的析构器。

      2.4 弱引用(weak references)

    static WeakReference data;
    public  static void Run()
    {
        object result = GetData();
        //GC.Collect(); 取消这行注释将会导致data.Target为null
        result = getData();
    } 
    private static object GetData()
    {
        if (data == null)
            data = new WeakReference(LoadLargeList());
    
        if (data.Target == null)
            data.Target = LoadLargeList();
    
        return data.Garget;
    }

       弱引用可用于缓存场景,用弱引用定义的对象,不会阻碍垃圾回收器的回收。上面的GetData方法,确保在对象被回收以后,重新获取并保存对象。

    3. 总结

      ① C#中,用堆和栈在内存中保存数据项。堆空间是受垃圾回收器管理的。

      ② 垃圾回收器会释放堆上那些已经不存在引用的对象。

      ③ 析构器是类中一段特殊的代码,在类对象被删除的时候,由垃圾回收器负责调用。

      ④ IDisposable接口,可以实现用可控的方式来释放非托管资源。

      ⑤ 可以用using关键字来确保实现了IDisposable的对象总会被成功释放。

      ⑥ 弱引用 可以保存一个对象,该对象会被垃圾回收器当做已经没有引用的对象而回收。

    转载于:https://www.cnblogs.com/stone_lv/p/4369539.html

    展开全文
  • with是我们常用上下文管理运行机制,今天这篇博文主要用于理解上下文管理协议运行机制,了解机制后方便我们自己查看他人代码。 如何让对象可以兼容with语句 让一个python中class可以支持with语句,必须要在...
  • OpenDDS是对象管理规范“实时系统数据分发服务”(DDS)以及其他一些相关规范开源C ++实现。 这些标准定义了一组接口和协议,用于基于发布-订阅和分布式缓存模型开发分布式应用程序。 尽管OpenDDS本身是用C...
  • 前端管理界面是由 Ext JS 用户界面组件驱动。前端和后端之间沟通是基于纯粹异步 JavaScript (Ajax) 和 XML 。 开发者还可以通过插件和widget (扩展部件) 对进行扩展。扩展可以通过使用一个专门插件...
  • 一、变味易用性 Unity是一款主打易用性游戏引擎。...目前,Unity几乎已经成为手游开发首选方案了,自身功能和各种围绕它技术生态日趋完善,C#语言也当仁不让地成为首选开发语言。 但是,她骨子...
  • 我们使用CodeIgniter 框架最主要是想利用 MVC ...在上一课中,我们用面向对象的方法大大简化了程序结构,将主要工作放在两个类中进行 ,URI 和 Router 类。 但是在 Router 类构造函数中为了获得 uri 实例...
  • 引用计数与对象生存期管理

    千次阅读 2009-05-20 09:33:00
    烽驿2009开源实时通信平台 源码获取:svn ...目前流行的对象生存期管理手段主要是各类垃圾回收(GC)机制。优点是使用简单,程序员只需负责对象创建,而不用关心对象销毁,但垃圾回收机制通常和语言本身绑定,主要
  • 20.1.1.2 TStream的实现原理    TStream对象是Stream对象的...因此,了解TStream是掌握Stream对象管理的核心。Borland公司虽然提供了Stream对象的接口说明文档,但对于实现和应用方法却没有提及,笔者是从Borl
  • 由于BOM主要用于管理窗口与窗口之间通讯,因此核心对象是window BOM由一系列相关对象构成,并且每个对象都提供了很多方法与属性   BOM 与 DOM 结构图 Browser Objects (BOM) {
  • BOM主要用于管理窗口与窗口之间通讯,因此核心对象是window BOM由一些列相关对象构成,并且每个对象提供 很多方法与属性 BOM缺乏标准,javascript 语法标准组织是ECMA,DOM标准组织是W3C BOM 最初是Netscape...
  • BOM主要用于管理窗口与窗口之间通讯,核心对象是window。Window对象有4个子对象history对象、location对象、navigator对象、screen对象。 BOM结构图 我们先来看一下window对象 一.窗口尺寸 ...
  • 处理机调度分为:1. 高级调度(High Level Scheduling)2....存储器是计算机系统重要的组成部分,其管理的主要对象是内存,如何对它进行有效的管理,不仅直接影响到存储器的利用率,而且对系统性能也有重大影响。
  • 我们都知道Spring中IOC(控制反转)就是将原来又程序员控制的对象(bean)反转来交给Spring帮我们管理。自然而然这里beans就是我们Java应用中需要使用到的对象集合。所有我说这个核心中核心,因为你没有了bean...
  • 这一部分我们主要看看oracle是如何管理权限和角色,权限和角色区别在哪里。 当刚刚建立用户时,用户没有任何权限,也不能执行任何操作。如果要执行某种特定数据库操作,则必须为授予系统权限;如果用户要...
  • spring是一个分层一站式开源框架,是为了解决企业开发复杂性而开发主要优势其的分层结构由七个不同层次组成。 spring架构图。 1.核心容器:核心容器提供了spring框架基本功能,主要组件为...
  • Propel主要依靠来管理依赖关系,但是您也可以使用 (例如,请参见autoload.php.dist文件)。 安装 阅读。 有助于 每个人都可以为Propel贡献力量。 只需对进行分叉,然后发送“拉取请求”即可。 您必须遵守并尽...
  • 三种造成内存泄漏的主要原因:1、Stack类自己管理内存。存储池包含了elements数组(对象引用单元,而不是对象本身)的元素,只要类是自己管理内存,程序员就应该警惕内存泄漏问题。Stack先是增长,然后再收缩,Stack...
  • 线程最主要的目的就是提高程序运行性能,线程可以使程序更加充分地发挥系统可用处理能力,从而提高系统资源利用率,但是在有多个线程访问同一个对象时,我们就要保证安全性。 要编写线程安全代码,核心...
  • 众所周知,Spring的核心技术是IOC容器,利用可以更方便的创建和管理对象之间的依赖关系,所以今天详细讲解IOC容器创建对象的主要方式来加以理解。 创建对象的3种主要方式: 无参构造器创建对象 有参构造器创建...
  • 什么是对象存储

    2011-12-14 09:26:22
    块是存储基础架构,对块的管理是简单。从全球第一个磁盘存储技术50 年前诞生到现在,块技术没有发生太大变化。磁盘工业生产遍及全球。最近几年,存储行业兴起存储虚拟化和数据整合新概念,在这些概念和方案...
  • 从三个方面来说,主要有方面措施:对象的引用计数机制、垃圾回收机制、内存池机制。一、对象的引用计数机制Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。引用计数增加情况:1、一个...
  • 这个项目是个主要是实现员工各种信息增删改查并且在控制台设置客户端 项目实现 首先这个项目需要一个员工基本信息类,还需要实现增删改查功能类,最后一个main入口 设置控制台输入输出类 话不多说上代码 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,654
精华内容 1,061
关键字:

其管理的主要对象是