电子商城网站如何建设html网页制作表格代码
电子商城网站如何建设,html网页制作表格代码,福建省建筑信息平台,网站开发用什么编程如何确定一个对象是垃圾#xff1f; 要想进行垃圾回收#xff0c;得先知道什么样的对象是垃圾。 引用计数法 循环引用 引用 -- 对象--数据
对于某个对象而言#xff0c;只要应用程序中持有该对象的引用#xff0c;就说明该对象不是垃圾#xff0c;如果一个对象没有任何指…如何确定一个对象是垃圾要想进行垃圾回收得先知道什么样的对象是垃圾。引用计数法 循环引用 引用 -- 对象--数据对于某个对象而言只要应用程序中持有该对象的引用就说明该对象不是垃圾如果一个对象没有任何指针对其引用它就是垃圾。弊端:如果AB相互持有引用导致永远不能被回收。 循环引用 内存泄露 --内存溢出可达性分析/根搜索算法从根上引用出一条单向的引用链而在这个单向的引用链之上的对象我们称之为GC的可达对象不在引用链上的对象 我们称之为垃圾通过GC Root的引用开始向下寻找看某个对象是否可达能作为GC Root:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等。 GC ROOT是根对象 错误 GC root 的本质是一组你可以直接或者间接使用的活跃引用虚拟机栈栈帧中的本地变量表中引用的对象。 方法区中类静态属性引用的对象。 方法区中常量引用的对象。 本地方法栈中JNI即一般说的Native方法引用的对象。 java native interface垃圾收集算法已经能够确定一个对象为垃圾之后接下来要考虑的就是回收怎么回收呢得要有对应的算法下面介绍常见的垃圾回收算法。高效 健壮 数据结构 算法标记-清除(Mark-Sweep)标记找出内存中所有的存活对象并且把它们标记出来清除清除掉被没有被标记需要回收的对象释放出对应的内存空间缺点标记清除之后会产生大量不连续的内存碎片空间碎片太多可能会导致以后在程 序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。 (1)标记和清除两个过程都比较耗时效率不高 (2)会产生大量不连续的内存碎片空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。标记清除算法的衍生规则之分配动态分区分配策略首次适应算法Fisrt-fit首次适应算法Fisrt-fit就是在遍历空闲链表的时候一旦发现有大小大于等于需要的大小之后就立即把该块分配给对象并立即返回。最佳适应算法Best-fit最佳适应算法Best-fit就是在遍历空闲链表的时候返回刚好等于需要大小的块。最差适应算法Worst-fit最差适应算法Worst-fit就是在遍历空闲链表的时候找出空闲链表中最大的分块将其分割给申请的对象其目的就是使得分割后分块的最大化以便下次好分配不过这种分配算法很容易产生很多很小的分块这些分块也不能被使用什么是STWstop the worldStop-The-World 简称 STW是在垃圾回收算法执行过程中,将jvm内存冻结,停顿的一种状态在Stw情况下容易出现两种现象该回收的对象没有被回收不该回收的对象被回收了在STW状态下,所有的线程都是停止运行的 - 垃圾回收线程除外当STW发生时,出了GC所需要的线程,其他的线程都将停止工作,中断了的线程知道GC线程结束才会继续任务STW是不可避免的,垃圾回收算法的执行一定会出现STW,而我们最好的解决办法就是减少停顿的时间GC各种算法的优化重点就是为了减少STW,这也是JVM调优的重点。标记-复制(Mark-Copying) 效率很高将内存划分为两块相等的区域每次只使用其中一块如下图所示当其中一块内存使用完了就将还存活的对象复制到另外一块上面然后把已经使用过的内存空间一次清除掉。缺点:空间利用率降低。标记-整理(Mark-Compact) 标记压缩算法随机整理 线性整理 滑动整理复制收集算法在对象存活率较高时就要进行较多的复制操作效率将会变低。更关键的是如果不想浪费50%的空间就需要有额外的空间进行分配担保以应对被使用的内存中所有对象都有100%存活的极端情况所以老年代一般不能直接选用这种算法。标记过程仍然与标记-清除算法一样但是后续步骤不是直接对可回收对象进行清理而是让所有存活的对象都向一端移动然后直接清理掉端边界以外的内存。其实上述过程相对复制算法来讲少了一个保留区让所有存活的对象都向一端移动清理掉边界意外的内存。分代收集算法既然上面介绍了3中垃圾收集算法那么在堆内存中到底用哪一个呢Young区复制算法(对象在被分配之后可能生命周期比较短Young区复制效率比较高)Old区标记清除或标记整理(Old区对象存活时间比较长复制来复制去没必要不如做个标记再清理)其他算法增量回收算法垃圾回收其实就是对不需要的内存对象进行清理前面提到的GC算法无论哪种基本都是过一段时间对所有的内存空间对象进行一次大扫除。 这种的GC缺点是一旦开始启动管理程序可能就停止了表现就是可能好多程序都没响应。可在服务端这是大忌。增量式incremental出现就是解决这个问题的这种垃圾回收采用和应用程序交替进行的方式来工作表现就像是GC在不断的定时迭加操作。从而尽量减轻应用程序的停止时间这就是增量式回收的特点。 在增量式回收里比较容易接触到的就是三色标记算法。三色标记在并发标记的过程中因为标记期间应用线程还在继续跑对象间的引用可能发生变化多标和漏标的情况就有可能发生。这里引入“三色标记”来给大家解释下把Gc roots可达性分析遍历对象过程中遇到的对象 按照“是否访问过”这个条件标记成以下三种颜色灰色表示对象已经被垃圾收集器访问过 但这个对象上至少存在一个引用还没有被扫描过。白色:表示对象尚未被垃圾收集器访问过。 显然在可达性分析刚刚开始的阶段 所有的对象都是白色的 若在分析结束的阶段 仍然是白色的对象 即代表不可达。黑色表示对象已经被垃圾收集器访问过 且这个对象的所有引用都已经扫描过。 黑色的对象代表已经扫描过 它是安全存活的 如果有其他对象引用指向了黑色对象 无须重新扫描一遍。 黑色对象不可能直接不经过灰色对象 指向某个白色对象。标记过程1.初始时所有对象都在 【白色集合】中2.将GC Roots 直接引用到的对象 挪到 【灰色集合】中3.从灰色集合中获取对象将本对象 引用到的 其他对象 全部挪到 【灰色集合】中将本对象 挪到 【黑色集合】里面。重复步骤3.4直至【灰色集合】为空时结束。结束后仍在【白色集合】的对象即为GC Roots 不可达可以进行回收多标-浮动垃圾在并发标记过程中如果由于方法运行结束导致部分局部变量(gcroot)被销毁这个gc root引用的对象之前又被扫描过 (被标记为非垃圾对象)那么本轮GC不会回收这部分内存。这部分本应该回收但是没有回收到的内存被称之为“浮动 垃圾”。浮动垃圾并不会影响垃圾回收的正确性只是需要等到下一轮垃圾回收中才被清除。 另外针对并发标记(还有并发清理)开始后产生的新对象通常的做法是直接全部当成黑色本轮不会进行清除。这部分 对象期间可能也会变为垃圾这也算是浮动垃圾的一部分。漏标-读写屏障漏标只有同时满足以下两个条件时才会发生条件一灰色对象 断开了 白色对象的引用即灰色对象 原来成员变量的引用 发生了变化。 条件二黑色对象 重新引用了 该白色对象即黑色对象 成员变量增加了 新的引用。漏标会导致被引用的对象被当成垃圾误删除这是严重bug必须解决有两种解决方案增量更新Incremental Update 和原始快照Snapshot At The BeginningSATB。增量更新就是当黑色对象插入新的指向白色对象的引用关系时 就将这个新插入的引用记录下来 等并发扫描结束之后 再将这些记录过的引用关系中的黑色对象为根 重新扫描一次。 这可以简化理解为 黑色对象一旦新插入了指向白色对象的引用之后 它就变回灰色对象了。原始快照就是当灰色对象要删除指向白色对象的引用关系时 就将这个要删除的引用记录下来 在并发扫描结束之后 再将这些记录过的引用关系中的灰色对象为根 重新扫描一次这样就能扫描到白色的对象将白色对象直接标记为黑色(目的就是让这种对象在本轮gc清理中能存活下来待下一轮gc的时候重新扫描这个对象也有可能是浮动垃圾)以上无论是对引用关系记录的插入还是删除 虚拟机的记录操作都是通过写屏障实现的。写屏障实现原始快照SATB当对象B的成员变量的引用发生变化时比如引用消失a.b.d null我们可以利用写屏障将B原来成员变量的引用对象D记录下来写屏障实现增量更新当对象A的成员变量的引用发生变化时比如新增引用a.d d我们可以利用写屏障将A新的成员变量引用对象D 记录下来垃圾收集器如果说收集算法是内存回收的方法论那么垃圾收集器就是内存回收的具体实现。SerialSerial收集器是最基本、发展历史最悠久的收集器曾经在JDK1.3.1之前是虚拟机新生代收集的唯一选择。它是一种单线程收集器不仅仅意味着它只会使用一个CPU或者一条收集线程去完成垃圾收集工作更重要的是其在进行垃圾收集的时候需要暂停其他线程。优点简单高效拥有很高的单线程收集效率 缺点收集过程需要暂停所有线程 算法复制算法 适用范围新生代 应用Client模式下的默认新生代收集器Serial OldSerial Old收集器是Serial收集器的老年代版本也是一个单线程收集器不同的是采用标记-整理算法运行过程和Serial收集器一样。ParNew可以把这个收集器理解为Serial收集器的多线程版本。优点在多CPU时比Serial效率高。 缺点收集过程暂停所有应用程序线程单CPU时比Serial效率差。 算法复制算法 适用范围新生代 应用运行在Server模式下的虚拟机中首选的新生代收集器Parallel ScavengeParallel Scavenge收集器是一个新生代收集器它也是使用复制算法的收集器又是并行的多线程收集器看上去和ParNew一样但是Parallel Scanvenge更关注系统的吞吐量。吞吐量运行用户代码的时间/(运行用户代码的时间垃圾收集时间)比如虚拟机总共运行了100分钟垃圾收集时间用了1分钟吞吐量(100-1)/10099%。若吞吐量越大意味着垃圾收集的时间越短则用户代码可以充分利用CPU资源尽快完成程序的运算任务。-XX:MaxGCPauseMillis控制最大的垃圾收集停顿时间 -XX:GCRatio直接设置吞吐量的大小。Parallel Old 停顿时间 吞吐量 百分比的数字Parallel Old收集器是Parallel Scavenge收集器的老年代版本使用多线程和标记-整理算法进行垃圾回收也是更加关注系统的吞吐量。CMS官网 https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collectorCMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。采用的是标记-清除算法,整个过程分为4步(1)初始标记 CMS initial mark 标记GC Roots直接关联对象不用Tracing速度很快 (2)并发标记 CMS concurrent mark 进行GC Roots Tracing (3)重新标记 CMS remark 修改并发标记因用户程序变动的内容 (4)并发清除 CMS concurrent sweep 清除不可达对象回收空间同时有新垃圾产生留着下次清理称为浮动垃圾由于整个过程中并发标记和并发清除收集器线程可以与用户线程一起工作所以总体上来说CMS收集器的内存回收过程是与用户线程一起并发地执行的。优点并发收集、低停顿 缺点产生大量空间碎片、并发阶段会降低吞吐量什么是记忆集当我们进行young gc时我们的gc roots除了常见的栈引用、静态变量、常量、锁对象、class对象这些常见的之外如果老年代有对象引用了我们的新生代对象那么老年代的对象也应该加入gc roots的范围中但是如果每次进行young gc我们都需要扫描一次老年代的话那我们进行垃圾回收的代价实在是太大了因此我们引入了一种叫做记忆集的抽象数据结构来记录这种引用关系。记忆集是一种用于记录从非收集区域指向收集区域的指针集合的数据结构。如果我们不考虑效率和成本问题我们可以用一个数组存储所有有指针指向新生代的老年代对象。但是如果这样的话我们维护成本就很好打个比方假如所有的老年代对象都有指针指向了新生代那么我们需要维护整个老年代大小的记忆集毫无疑问这种方法是不可取的。因此我们引入了卡表的数据结构卡表记忆集是我们针对于跨代引用问题提出的思想而卡表则是针对于该种思想的具体实现。可以理解为记忆集是结构卡表是实现类[1字节000000001字节1字节]在hotspot虚拟机中卡表是一个字节数组数组的每一项对应着内存中的某一块连续地址的区域如果该区域中有引用指向了待回收区域的对象卡表数组对应的元素将被置为1没有则置为0(1) 卡表是使用一个字节数组实现:CARD_TABLE[],每个元素对应着其标识的内存区域一块特定大小的内存块,称为卡页。hotSpot使用的卡页是2^9大小,即512字节(2) 一个卡页中可包含多个对象,只要有一个对象的字段存在跨代指针,其对应的卡表的元素标识就变成1,表示该元素变脏,否则为0。GC时,只要筛选本收集区的卡表中变脏的元素加入GC Roots里。卡表的使用图例并发标记的时候A对象发生了所在的引用发生了变化所以A对象所在的块被标记为脏卡继续往下到了重新标记阶段修改对象的引用同时清除脏卡标记。卡表其他作用老年代识别新生代的时候对应的card table被标识为相应的值card table中是一个byte有八位约定好每一位的含义就可区分哪个是引用新生代哪个是并发标记阶段修改过的