オブジェクトを作成するためのメモリとメモリオーバーフロー例外のJavaの面積、

ランタイムデータ領域

    

  Javaのプログラム実行フロー:まずの.javaソースコードファイルは、Javaバイトコードファイルなどのコンパイラ(の.classサフィックス)、およびは、その後、負荷JVMのクラスローダによって、各クラスのバイトコードファイル、読み込みが完了した後、実行(イン・タイム・コンパイラ、ガベージコレクタを含む)をいうJVM実行エンジン。プログラム全体の実行の過程で、JVMは、プログラムを格納するスペースの実行期間中にデータや情報を使用する必要があります、このスペースは、実行時データ領域と呼ばれています。

  1.プログラムカウンタは:小さなメモリ空間であり、それが実行される現在の行番号インジケータスレッドバイトコードとして考えることができ、それはプライベートなスレッドであるので、各スレッドは、別のプログラムカウンタを有し、このメモリ地域には、Java仮想マシン仕様で任意のOutOfMemoryErrorが(OOM)の状況を提供していない領域のみです。

  2.Java仮想マシン・スタック:スレッドプライベート、そのライフサイクルと同じスレッドがあります。各方法において、(すべての基本データ型に格納され、コンパイル知り得る、及びRETURNADDRESSオブジェクト参照型)ローカル変数テーブルを格納するためのスタックフレームを作成するために、同時に実行される仮想マシン・スタックのJavaメモリ・モデルは、メソッドが実行さ説明しました、オペランド輸出用スタック、動的リスト、およびその他の情報。スタックのスタックから仮想マシンのスタックのスタックフレームの処理に相当するの完全な実行に各メソッド呼び出しから。

    例外:スタックは、スレッドの深さは、仮想マシンの許容深さを要求されたよりも大きい場合、にStackOverflowError例外をスローします。

         動的な拡張がOOM例外がスローされます場合は、仮想マシンに十分なメモリを適用することはできません。

    ソリューション:SOFは異常が現れたため、スタックはエラーを読み込むことによって、問題を見つけることができます。OOM例外のため、スレッド数を低下させることなく、高仮想マシンを交換する、唯一のより多くのと引き換えに最大ヒープとスタック容量低下を低減することにより、スレッド。

  3.ネイティブメソッドスタック:仮想マシンの使用がネイティブメソッドを提供するために、スレッドはプライベートです。SOFとそれがOOM例外がスローされます。

  4.Javaヒープ:データ領域内のすべてのスレッドで共有されています。時に仮想マシンの起動作成し、その目的は、オブジェクトのインスタンスを格納し、オブジェクトのインスタンスのメモリを割り当てることで、Javaのヒープガベージコレクタは、メイン領域管理であるため、Javaヒープは新世代と古い時代に細分化することができます。

    例外は:そこにヒープメモリの割り当てには完全な例ではありません、そしてスタックはもはや広げることができれば、それはOOM例外がスローされます。

    ソリューション:まず、ダンプ、それが最後にクリアにするヒープダンプ解析ツールのメモリマップされたスナップショットで分析し、メモリリークやメモリのオーバーフローであり、それはメモリリークがある場合、あなたはどのような経路を通って漏れているツールで、さらにオブジェクトを見つけることができますGCのルーツは、関連付け、ガベージコレクタへのリードは、それらを自動的に回復することはできません、情報はオブジェクト型の情報と参考文献のGCのルーツチェーンは、あなたがより正確にリークしたコードの位置を突き止めることができます漏洩してい;漏れが存在しない場合、それは、メモリがありますオブジェクトは生きている必要があり、それがパラメータは、特定のオブジェクトのライフサイクルの存在のためのチェックは長すぎる、長すぎる状態で保持されているコードから、あなたはまだ上げることができるかどうかを確認するために、仮想マシンの物理メモリとその比較をチェックする必要がありますヒープう場合は、実行中にメモリ消費量を削減してみてください。

  メソッド領域は:仮想マシンにロードされたクラス情報を格納するためのスレッド共有メモリ領域、定数、静的変数、コードデータのタイムコンパイラの変異です。加えて、この方法は非常にリラックスしたエリアでのJava仮想マシン仕様の制限、およびJavaのヒープメモリのような連続必要とせず、一定のサイズを選択することができますまたは拡張することができるが、また、ガベージコレクションを実装しないことを選択することができます。このエリアには、荷降ろしの定数プールの種類のゴミ回収・リサイクルのために主にあります。

  実行時定数プールは、種々のリテラルとコンパイル生成された基準シンボルを記憶するための方法の領域の一部であり、この部分は、ゾーン時定数ストレージプールロードされたクラスのメソッドで実行するようになります。

    例外:メモリ割り当て領域の方法は、ニーズを満たすことができない場合、OOM例外がスローされます。

    ソリューション:リサイクルのために無用のGCクラスをロードします。

  直接内存不是虚拟机运行时数据区的一部分,但是这部分内存也被频繁使用。本机直接内存不受Java堆大小的限制,但会受到本地总内存大小及处理器寻址空间的限制。NIO类引入了一种基于通道和缓冲区的IO方法,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。

    异常情况:当各个内存区域总和大于物理内存限制,导致动态扩展时出现OOM异常。

二、对象的创建过程

  当虚拟机遇到一条new指令时,首先先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行类的加载过程。

  在类加载检查通过后,虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成时就已经确定;选择哪种分配方式由Java堆是否规整决定如果Java堆中的内存是规整的,所有用过的内存放在一边,空闲内存放在另一边,中间放着一个指针作为临界指示器,那分配内存就是把指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方法称为指针碰撞如果Java堆中内存是不规整的,虚拟机就必须维护一个列表,用来记录哪块内存时可用的,在分配时从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方法称为空闲列表

  另外在多线程情况下,对象创建并不是线程安全的,可能出现正给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况。解决这种问题的方案,一种是对分配内存空间的动作进行同步处理--实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性;另一种是把内存分配的动作按照线程划分在不同的空间进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。

  内存分配完成后,虚拟机需要将分配到内存空间都初始化为零值。这一操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用。接下来,虚拟机对对象进行必要的设置,并将这些设置存放在对象的对象头中。最后执行 init方法把对象按照意愿进行初始化,这样一个真正可用的对象就产生了。

三、对象的布局

  对象在内存中存储的布局可以分为:对象头、实例数据和对齐填充。对象头包括两部分信息:一部分用于存储对象自身的运行时数据;另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针确定这个对象是哪个类的实例。实例数据部分是对象真正存储的有效信息。对齐填充并不是必然存在的,它仅仅起到占位符的作用。

四、对象的访问定位

  如果使用句柄访问的话,那么Java堆将会划分一块内存来作为句柄池,referance中存储的是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。

    使用句柄访问的好处就是referance中存储的是稳定的句柄地址,在对象被移动时只会改变句柄的实例数据指针,而referance本身不需要修改。

  如果使用直接指针访问,那么Java堆对象的布局就必须考虑如何放置访问类型数据的相关信息,而referance中存储的直接是对象的地址。

    使用直接指针访问的好处就是速度快,它节省了一次指针定位的开销。

おすすめ

転載: www.cnblogs.com/HuiH/p/11972170.html