国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何在Java中分配超過-Xmx限制的內(nèi)存

qiangdada / 2458人閱讀

摘要:不幸的是,在里,由于數(shù)組元素的類型的限制,你操作起內(nèi)存來會(huì)比較麻煩。這和的工作方式類似,不過它拷貝的是字節(jié)而不是數(shù)組元素。這個(gè)頭的長(zhǎng)度可以通過方法來獲取到,這里是數(shù)組元素的類型。注意分配出來的內(nèi)存是無法進(jìn)行垃圾回收的。

本文主要介紹Java中幾種分配內(nèi)存的方法。我們會(huì)看到如何使用sun.misc.Unsafe來統(tǒng)一操作任意類型的內(nèi)存。以前用C語言開發(fā)的同學(xué)通常都希望能在Java中通過較底層的接口來操作內(nèi)存,他們一定會(huì)對(duì)本文中要講的內(nèi)容感興趣。

如果你對(duì)Java內(nèi)存優(yōu)化比較感興趣,可以看下這篇文章,以及它的姊妹篇:一, 二。

數(shù)組分配的上限

Java里數(shù)組的大小是受限制的,因?yàn)樗褂玫氖莍nt類型作為數(shù)組下標(biāo)。這意味著你無法申請(qǐng)超過Integer.MAX_VALUE(2^31-1)大小的數(shù)組。這并不是說你申請(qǐng)內(nèi)存的上限就是2G。你可以申請(qǐng)一個(gè)大一點(diǎn)的類型的數(shù)組。比如:

final long[] ar = new long[ Integer.MAX_VALUE ];

這個(gè)會(huì)分配16G -8字節(jié),如果你設(shè)置的-Xmx參數(shù)足夠大的話(通常你的堆至少得保留50%以上的空間,也就是說分配16G的內(nèi)存,你得設(shè)置成-Xmx24G。這只是一般的規(guī)則,具體分配多大要看實(shí)際情況)。

不幸的是,在Java里,由于數(shù)組元素的類型的限制,你操作起內(nèi)存來會(huì)比較麻煩。在操作數(shù)組方面,ByteBuffer應(yīng)該是最有用的一個(gè)類了,它提供了讀寫不同的Java類型的方法。它的缺點(diǎn)是,目標(biāo)數(shù)組類型必須是byte[],也就是說你分配的內(nèi)存緩存最大只能是2G。

把所有數(shù)組都當(dāng)作byte數(shù)組來進(jìn)行操作

假設(shè)現(xiàn)在2G內(nèi)存對(duì)我們來說遠(yuǎn)遠(yuǎn)不夠,如果是16G的話還算可以。我們已經(jīng)分配了一個(gè)long[],不過我們希望把它當(dāng)作byte數(shù)組來進(jìn)行操作。在Java里我們得求助下C程序員的好幫手了——sun.misc.Unsafe。這個(gè)類有兩組方法:getN(object, offset),這個(gè)方法是要從object偏移量為offset的位置獲取一個(gè)指定類型的值并返回它,N在這里就是代表著那個(gè)要返回值的類型,而putN(Object,offset,value)方法就是要把一個(gè)值寫到Object的offset的那個(gè)位置。

不幸的是,這些方法只能獲取或者設(shè)置某個(gè)類型的值。如果你從數(shù)組里拷貝數(shù)據(jù),你還需要unsafe的另一個(gè)方法,copyMemory(srcObject, srcOffset, destObject,destOffet,count)。這和System.arraycopy的工作方式類似,不過它拷貝的是字節(jié)而不是數(shù)組元素。

想通過sun.misc.Unsafe來訪問數(shù)組的數(shù)據(jù),你需要兩個(gè)東西:

數(shù)組對(duì)象里數(shù)據(jù)的偏移量

拷貝的元素在數(shù)組數(shù)據(jù)里的偏移量

Arrays和Java別的對(duì)象一樣,都有一個(gè)對(duì)象頭,它是存儲(chǔ)在實(shí)際的數(shù)據(jù)前面的。這個(gè)頭的長(zhǎng)度可以通過unsafe.arrayBaseOffset(T[].class)方法來獲取到,這里T是數(shù)組元素的類型。數(shù)組元素的大小可以通過unsafe.arrayIndexScale(T[].class) 方法獲取到。這也就是說要訪問類型為T的第N個(gè)元素的話,你的偏移量offset應(yīng)該是arrayOffset+N*arrayScale

你可以看下這篇文章里,UnsafeMemory類使用Unsafe訪問內(nèi)存的那個(gè)例子。

我們來寫個(gè)簡(jiǎn)單的例子吧。我們分配一個(gè)long數(shù)組,然后更新它里面的幾個(gè)字節(jié)。我們把最后一個(gè)元素更新成-1(16進(jìn)制的話是0xFFFF FFFF FFFF FFFF),然再逐個(gè)清除這個(gè)元素的所有字節(jié)。

final long[] ar = new long[ 1000 ];
final int index = ar.length - 1;
ar[ index ] = -1; //FFFF FFFF FFFF FFFF

System.out.println( "Before change = " + Long.toHexString( ar[ index ] ));

for ( long i = 0; i < 8; ++i )
{
    unsafe.putByte( ar, longArrayOffset + 8L * index + i, (byte) 0);
    System.out.println( "After change: i = " + i + ", val = "  +  Long.toHexString( ar[ index ] ));
}

想運(yùn)行上面 這個(gè)例子的話,得在你的測(cè)試類里加上下面的靜態(tài)代碼塊:

private static final Unsafe unsafe;
static
{
    try
    {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        unsafe = (Unsafe)field.get(null);
    }
    catch (Exception e)
    {
        throw new RuntimeException(e);
    }
}

private static final long longArrayOffset = unsafe.arrayBaseOffset(long[].class);

輸出的結(jié)果是:

Before change = ffffffffffffffff
After change: i = 0, val = ffffffffffffff00
After change: i = 1, val = ffffffffffff0000
After change: i = 2, val = ffffffffff000000
After change: i = 3, val = ffffffff00000000
After change: i = 4, val = ffffff0000000000
After change: i = 5, val = ffff000000000000
After change: i = 6, val = ff00000000000000
After change: i = 7, val = 0
sun.misc.Unsafe的內(nèi)存分配

上面也說過了,在純Java里我們的能分配的內(nèi)存大小是有限的。這個(gè)限制在Java的最初版本里就已經(jīng)定下來了,那個(gè)時(shí)候人們都不敢相像分配好幾個(gè)G的內(nèi)存是什么情況。不過現(xiàn)在已經(jīng)是大數(shù)據(jù)的時(shí)代了,我們需要更多的內(nèi)存。在Java里,想獲取更多的內(nèi)存有兩個(gè)方法:

分配許多小塊的內(nèi)存,然后邏輯上把它們當(dāng)作一塊連續(xù)的大內(nèi)存來使用。

使用sun.misc.Unsafe.allcateMemory(long)來進(jìn)行內(nèi)存分配。

第一個(gè)方法只是從算法的角度來看比較有意思一點(diǎn),所以我們還是來看下第二個(gè)方法。

sun.misc.Unsafe提供了一組方法來進(jìn)行內(nèi)存的分配,重新分配,以及釋放。它們和C的malloc/free方法很像:

long Unsafe.allocateMemory(long size)——分配一塊內(nèi)存空間。這塊內(nèi)存可能會(huì)包含垃圾數(shù)據(jù)(沒有自動(dòng)清零)。如果分配失敗的話會(huì)拋一個(gè)java.lang.OutOfMemoryError的異常。它會(huì)返回一個(gè)非零的內(nèi)存地址(看下面的描述)。

Unsafe.reallocateMemory(long address, long size)——重新分配一塊內(nèi)存,把數(shù)據(jù)從舊的內(nèi)存緩沖區(qū)(address指向的地方)中拷貝到的新分配的內(nèi)存塊中。如果地址等于0,這個(gè)方法和allocateMemory的效果是一樣的。它返回的是新的內(nèi)存緩沖區(qū)的地址。

Unsafe.freeMemory(long address)——釋放一個(gè)由前面那兩方法生成的內(nèi)存緩沖區(qū)。如果address為0什么也不干 。

這些方法分配的內(nèi)存應(yīng)該在一個(gè)被稱為單寄存器地址的模式下使用:Unsafe提供了一組只接受一個(gè)地址參數(shù)的方法(不像雙寄存器模式,它們需要一個(gè)Object還有一個(gè)偏移量offset)。通過這種方式分配的內(nèi)存可以比你在-Xmx的Java參數(shù)里配置的還要大。

注意:Unsafe分配出來的內(nèi)存是無法進(jìn)行垃圾回收的。你得把它當(dāng)成一種正常的資源,自己去進(jìn)行管理。

下面是使用Unsafe.allocateMemory分配內(nèi)存的一個(gè)例子,同時(shí)它還檢查了整個(gè)內(nèi)存緩沖區(qū)是不是可讀寫的:

final int size = Integer.MAX_VALUE / 2;
final long addr = unsafe.allocateMemory( size );
try
{
    System.out.println( "Unsafe address = " + addr );
    for ( int i = 0; i < size; ++i )
    {
        unsafe.putByte( addr + i, (byte) 123);
        if ( unsafe.getByte( addr + i ) != 123 )
            System.out.println( "Failed at offset = " + i );
    }
}
finally
{
    unsafe.freeMemory( addr );
}

正如你所看見的,使用sun.misc.Unsafe你可以寫出非常通用的內(nèi)存訪問的代碼:不管是Java里分配的何種內(nèi)存,你都可以隨意讀寫任意類型的數(shù)據(jù)。

原文 Various types of memory allocation in Java
轉(zhuǎn)自 Java譯站

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/64063.html

相關(guān)文章

  • (轉(zhuǎn))JVM調(diào)優(yōu)

    摘要:是指設(shè)定程序運(yùn)行期間最大可占用的內(nèi)存大小。持久代一般固定大小為,所以增大年輕代后,將會(huì)減小年老代大小。更具應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整。但是操作系統(tǒng)對(duì)一個(gè)進(jìn)程內(nèi)的線程數(shù)還是有限制的,不能無限生成,經(jīng)驗(yàn)值在左右。此配置僅對(duì)年輕代有效。 1、freeMemory(), totalMemory(), maxMemory()比較 最近在網(wǎng)上看到一些人討論到j(luò)ava.lang.Runtime類...

    youkede 評(píng)論0 收藏0
  • JVM詳解1.Java內(nèi)存模型

    摘要:編譯參見深入理解虛擬機(jī)節(jié)走進(jìn)之一自己編譯源碼內(nèi)存模型運(yùn)行時(shí)數(shù)據(jù)區(qū)域根據(jù)虛擬機(jī)規(guī)范的規(guī)定,的內(nèi)存包括以下幾個(gè)運(yùn)運(yùn)行時(shí)數(shù)據(jù)區(qū)域程序計(jì)數(shù)器程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,他可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。 點(diǎn)擊進(jìn)入我的博客 1.1 基礎(chǔ)知識(shí) 1.1.1 一些基本概念 JDK(Java Development Kit):Java語言、Java虛擬機(jī)、Java API類庫JRE(...

    TANKING 評(píng)論0 收藏0
  • 淺析JVM之內(nèi)存管理

    摘要:概要要理解的內(nèi)存管理策略,首先就要熟悉的運(yùn)行時(shí)數(shù)據(jù)區(qū),如上圖所示,在執(zhí)行程序的時(shí)候,虛擬機(jī)會(huì)把它所管理的內(nèi)存劃分為多個(gè)不同的數(shù)據(jù)區(qū),稱為運(yùn)行時(shí)數(shù)據(jù)區(qū)。 這是一篇有關(guān)JVM內(nèi)存管理的文章。這里將會(huì)簡(jiǎn)單的分析一下Java如何使用從物理內(nèi)存上申請(qǐng)下來的內(nèi)存,以及如何來劃分它們,后面還會(huì)介紹JVM的核心技術(shù):如何分配和回收內(nèi)存。 JMM ( Java Memory Model )概要 show...

    Eric 評(píng)論0 收藏0
  • 十種JVM內(nèi)存溢出情況,你碰到過幾種?

    摘要:內(nèi)存溢出的情況就是從類加載器加載的時(shí)候開始出現(xiàn)的,內(nèi)存溢出分為兩大類和。以下舉出個(gè)內(nèi)存溢出的情況,并通過實(shí)例代碼的方式講解了是如何出現(xiàn)內(nèi)存溢出的。內(nèi)存溢出問題描述元空間的溢出,系統(tǒng)會(huì)拋出。這樣就會(huì)造成棧的內(nèi)存溢出。 導(dǎo)言: 對(duì)于java程序員來說,在虛擬機(jī)自動(dòng)內(nèi)存管理機(jī)制的幫助下,不需要自己實(shí)現(xiàn)釋放內(nèi)存,不容易出現(xiàn)內(nèi)存泄漏和內(nèi)存溢出的問題,由虛擬機(jī)管理內(nèi)存這一切看起來非常美好,但是一旦...

    ShevaKuilin 評(píng)論0 收藏0
  • JAVA中堆和棧區(qū)別

    摘要:堆內(nèi)存主要作用是存放運(yùn)行時(shí)創(chuàng)建的對(duì)象。堆內(nèi)存用來存放由創(chuàng)建的對(duì)象和數(shù)組,在堆中分配的內(nèi)存,由虛擬機(jī)的自動(dòng)垃圾回收器來管理。這也是比較占內(nèi)存的原因,實(shí)際上,棧中的變量指向堆內(nèi)存中的變量,這就是中的指針 堆:(對(duì)象) 引用類型的變量,其內(nèi)存分配在堆上或者常量池(字符串常量、基本數(shù)據(jù)類型常量),需要通過new等方式來創(chuàng)建。 堆內(nèi)存主要作用是存放運(yùn)行時(shí)創(chuàng)建(new)的對(duì)象。(主要用于存放對(duì)象,...

    RyanQ 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<