一 . 运行时数据区

程序计数器是线程私有的,是一块很小的内存空间,是当前线程执行到字节码行号的计数指示器。每个CPU处理器核心 在任何一个时刻,都只可能运行着唯一的一个线程,执行着一条指令。所以在多线程的应用中,线程不断切换和分配时间片。在线程切换来切换去的过程中,就是靠程序计数器来了解,该如果继续恢复运行该线程。

    虚拟机栈和Native方法栈也是线程私有的。在Sun HotSpot虚拟机中虚拟机栈和Native方法栈是被合二为一的。虚拟机栈描述的是Java方法执行的内存模型,栈帧用于存储局部变量表,方法出口等信息。每一个方法调用到执行完成都对应着一个栈帧在虚拟机栈中的入栈和出栈的过程。局部变量表中存放了八种基本数据类型和对象引用,还有returnAddress类型。前两种不难理解,returnAddress实际上是指向一条字节码指令的地址,局部变量表所需的内存空间在编译期间完成分配,当进入某个方法时,需要在栈帧中分配多大的局部空间是完全确定的,方法运行期间是不会改变局部变量表的大小。本地方法栈和虚拟机栈作用相似,虚拟机栈执行我们的java方法,本地方法栈就是执行Native方法,所以就是Native方法栈。简单地讲,一个Native Method就是一个java调用非java代码的接口。

Java堆是所有线程共享的区域,虚拟机管理的内存中最大的一块。基础所有对象的实例都是在这里分配内存。Java堆是GC的主要回收对象,虚拟机栈上局部变狼表所存的对象引用,就是指向堆内存中的一块地址。详细内容后面垃圾回收会提到更多。

    方法区也是一块所有线程共享的区域,这里存储虚拟机加载的类信息,常量,静态变量,JIT编译后的代码等数据。运行时常量池是方法区的一部分。

接下来要说到JVM GC机制,在垃圾回收中堆内存上移动对象位置是很常见的, 所以对象的访问方式也要顺便提一下,也可以展示下方法区的类型是如何被引用的。我们都知道栈上的局部变量表中,有存储reference数据的引用,它可能是对象的直接地址,也可能是句柄地址。

由于对象访问极其频繁,所以Hot Spot也使用第二种方式,直接存实例引用是效率比较高的。但是第一种句柄的方式,好处在于,垃圾回收中,不需要更改栈上所存储的地址,栈上的存储稳定,只需要修改句柄池。

二.垃圾回收GC

说到垃圾回收 ,就不得不说垃圾回收算法的思想, 说到回收算法, 又不得不想到,什么样的对象需要被回收?什么是存活对象,什么对象已死亡。判断对象的存活与死亡,通常有两种方法,引用计数法和可达性分析算法。引用计数算法的问题在于,无法解决两个对象间相互引用的问题,导致不得达的对象依然无法回收。下面是实例: 

A.b=B ;    //这里 B 引用计数+1   A对象在堆上   其属性b存着B的引用
B.a=A ; // 与上方同理
A=null;
B=null; //A B两对象栈上引用 给null AB堆上实例做到不可达
//此时导致 AB对象实例内存不会被回收

所以为了解决这个问题,Java虚拟机中 使用可达性分析算法。其思想是从可作为GC Root根结点的对象,向下搜索,搜索过的路成为引用链,凡事不能达到的对象,认为是可回收对象。有几种对象可以作为GC Root对象。

1. 虚拟机栈上(栈帧的本地变量表)引用的对象。   2. 方法区中类静态属性引用的对象。    3. 方法区中常量引用的对象      4.  本地方法栈上Native方法引用的对象。

试想一下,为什么这些对象可以作为GC Root,为什么其他对象无法作为GC Root。  比如你的一个接口,处理请求的时候,有很多线程本地变量 , 但是 处理完请求后,这些对象就都没用了,所以他们一般不能作为GC Root。什么时候本地变量会成为GC Root呢?  个人的猜测应该是在GC大面积回收,程序暂停的时候, 这个时候,不能把当前正在运行的数据和变量清理掉呀。这时候提升为GC Root是很恰当的我觉得。至于静态属性,常量什么的作为GC Root毋庸置疑了,他们本来生命周期就是整个应用程序生命周期。

    如何判断对象存活与死亡说过了,还需要了解的就是垃圾回收算法 。有四种思想需要提到, 其中有一种最基本的叫做 标记-清除算法。另外很重要的复制算法,是年轻代最合适的。还有一种标记整理算法,是老年代最合适的。最后一种就是分代这个思想。

    标记清除就是首先对所有需要回收的对象进行标记,最后统一进行清除。这样的做法效率不高,清理后内存碎片很多,可能导致后期大对象无法分配内存,会经常触发另一次垃圾回收。

    复制算法的思想是,将内存分为两块,其中一块保持为空,回收的时候,将存活的对象复制到空的一块,复制完成后,对原来那半内存全部清理。但是java虚拟机并不能留出一半的内存,这样太浪费资源,并且在Java堆中,年轻代里绝大部分内存都是要被回收的。所以Hot Spot中,将年轻代分为8:1:1的Eden,Survivor  * 2, 就是一块Eden , 两块Survivor。  所以年轻代的策略,优先使用大的Eden,必须保持一块Survivor为空。回收的时候,将存活的对象,复制到空的Survivor内存区域,清理Eden和刚才使用的Survivor。

如果Survivor放不下存活的对象了,和时候 就该有对象进入老年代了~     老年代使用标记—整理算法。标记整理思路就是,先标记,然后在回收的时候,将存活的对象移动到一端,将被清理的移动到另一端。然后清理端边界意外的内存。

  

  

C#写快速排序的更多相关文章

  1. 手写快速排序(QuickSort)

    #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; int ...

  2. 快速排序的php实现

    再来一个非常高级的排序算法,快速排序...这个算法是很高效的. 快速排序的思路是,找到一个分割点(中枢点 默认是列表第一个值),把原列表分隔成两部分,在分割点左侧的是都比它小的,在它右侧的是都比它大的 ...

  3. HDU 1425 sort(堆排序/快排/最大堆/最小堆)

    传送门 Description 给你n个整数,请按从大到小的顺序输出其中前m大的数. Input 每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不 ...

  4. C语言如何 实现 下雪效果

    题外话  前言 1.本文主要围绕 如何 在 控制台上 下起 一场 只有自己能看见的雪 2.是个简易跨平台的,主要是C语言 3.动画 采用 1s 40帧, 雪花具有 x轴速度和y轴速度 4.比较简单,可 ...

  5. C/C++面试题(一)

    1.手写快速排序 void quick_sort(int s[], int l, int r) { if (l < r) { //Swap(s[l], s[(l + r) / 2]); //将中 ...

  6. Java实现单向链表基本功能

    一.前言 最近在回顾数据结构与算法,有部分的算法题用到了栈的思想,说起栈又不得不说链表了.数组和链表都是线性存储结构的基础,栈和队列都是线性存储结构的应用- 本文主要讲解单链表的基础知识点,做一个简单 ...

  7. java:编程比赛中有用的方法整理(一)数组

    我曾经参加过几次编程比赛,但是当时用的是c语言,现在学习了java,打算专攻java组,故以此整理. 数组无论在哪里都必不可少. 一.数组的拷贝: 使用Arrays类的copyOf方法: 1.将一个数 ...

  8. python高级编程和算法

    import copy #a = ("a","b","c") #a = ["a","b"," ...

  9. 金三银四背后,一个 Android 程序员的面试心得

    回顾一下自己这段时间的经历,九月份的时候,公司通知了裁员,我匆匆忙忙地出去面了几家,但最终都没有拿到offer,我感觉今年的寒冬有点冷.到十二月份,公司开始第二波裁员,我决定主动拿赔偿走人.后续的面试 ...

随机推荐

  1. 【译】用jQuery 处理XML-- jQuery与XML

    用jQuery 处理XML--写在前面的话 用jQuery 处理XML-- DOM(文本对象模型)简介 用jQuery 处理XML--浏览器中的XML与JavaScript 用jQuery 处理XML ...

  2. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~续~添加事务机制

    回到目录 上一讲中简单介绍了一个EF环境下通过DbCommand拦截器来实现SQLSERVER的读写分离,只是一个最简单的实现,而如果出现事务情况,还是会有一些问题的,因为在拦截器中我们手动开启了Co ...

  3. C#设计模式-工厂模式

    引入人.工厂.和斧子的问题 原始社会时,劳动社会基本没有分工,需要斧子的人(调用者)只好自己去磨一把斧子,每个人拥有自己的斧子,如果把大家的石斧改为铁斧,需要每个人都要学会磨铁斧的本领,工作效率极低. ...

  4. iOS-SDWebImage

    我之前写过一篇博客,介绍缓存处理的三种方式,其中最难,最麻烦,最占内存资源的还是图片缓存,最近做的项目有大量的图片处理,还是采用了SDWebImage来处理,但是发现之前封装好的代码报错了.研究发现, ...

  5. Android 代码混淆之部分类不混淆的技巧

    在编写Android程序之后,我们通常要代码进行混淆编码,这样才能保证市场上我们的应用不会被别人进行反编译,然后破解,所以此时需要在发布正式版本的时候,有一些类事不能混淆的,比如实现了 Seriali ...

  6. Liferay7 BPM门户开发之42: Liferay核心JSP定制扩展

    Liferay最大的好处是不仅接口强大,利于扩展,就连JSP定制扩展都提供了3种方式. 修改核心jsp代码,有3种修改方式:1.暴力修改直接修改(位于portal-web/docroot/html), ...

  7. SeaJS与RequireJS最大的区别

    SeaJS与RequireJS最大的区别 U_U 2013-06-20 16:21:12 执行模块的机制大不一样-----------------------------------由于 Requir ...

  8. Render OpenCascade Geometry Surfaces in OpenSceneGraph

    在OpenSceneGraph中绘制OpenCascade的曲面 Render OpenCascade Geometry Surfaces in OpenSceneGraph eryar@163.co ...

  9. IO流-概览

    一. 抽象类InputStream和OutputStream构成了了IO类的基础 因为面向字节流的对象不便于处理Unicode形式储存的信息,所以从抽象类Reader和Writer中继承出专门用于处理 ...

  10. CSS全屏布局的5种方式

    × 目录 [1]float [2]inline-block [3]table[4]absolute[5]flex[6]总结 前面的话 全屏布局在实际工作中是很常用的,比如管理系统.监控平台等.本文将介 ...