最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中內(nèi)存分配的幾種方法

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

一、數(shù)組分配的上限

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

復(fù)制代碼 代碼如下:

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

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

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

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

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

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

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

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

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

復(fù)制代碼 代碼如下:

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)行上面 這個例子的話,得在你的測試類里加上下面的靜態(tài)代碼塊:
復(fù)制代碼 代碼如下:

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é)果是:

復(fù)制代碼 代碼如下:

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


1.分配許多小塊的內(nèi)存,然后邏輯上把它們當(dāng)作一塊連續(xù)的大內(nèi)存來使用。
2.使用sun.misc.Unsafe.allcateMemory(long)來進(jìn)行內(nèi)存分配。
第一個方法只是從算法的角度來看比較有意思一點(diǎn),所以我們還是來看下第二個方法。

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

1.long Unsafe.allocateMemory(long size)——分配一塊內(nèi)存空間。這塊內(nèi)存可能會包含垃圾數(shù)據(jù)(沒有自動清零)。如果分配失敗的話會拋一個java.lang.OutOfMemoryError的異常。它會返回一個非零的內(nèi)存地址(看下面的描述)。
2.Unsafe.reallocateMemory(long address, long size)——重新分配一塊內(nèi)存,把數(shù)據(jù)從舊的內(nèi)存緩沖區(qū)(address指向的地方)中拷貝到的新分配的內(nèi)存塊中。如果地址等于0,這個方法和allocateMemory的效果是一樣的。它返回的是新的內(nèi)存緩沖區(qū)的地址。
3.Unsafe.freeMemory(long address)——釋放一個由前面那兩方法生成的內(nèi)存緩沖區(qū)。如果address為0什么也不干 。

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

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

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

復(fù)制代碼 代碼如下:

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ù)。

 

相關(guān)文章

  • SpringBoot加載啟動的源碼解析

    SpringBoot加載啟動的源碼解析

    這篇文章主要介紹了SpringBoot加載啟動的源碼解析,@SpringBootApplication注解是Spring Boot的核心注解,它其實(shí)是一個組合注解,本身其實(shí)也是一個IoC容器的配置類,需要的朋友可以參考下
    2023-12-12
  • 一文詳解如何通過Java實(shí)現(xiàn)SSL交互功能

    一文詳解如何通過Java實(shí)現(xiàn)SSL交互功能

    這篇文章主要為大家詳細(xì)介紹了如何通過Java實(shí)現(xiàn)SSL交互功能,文中的示例代碼講解詳細(xì),對我們的學(xué)習(xí)或工作有一定的幫助,需要的可以參考一下
    2023-04-04
  • Java實(shí)現(xiàn)簡單的五子棋游戲示例代碼

    Java實(shí)現(xiàn)簡單的五子棋游戲示例代碼

    這篇文章主要為大家介紹了如何利用Java語言實(shí)現(xiàn)簡單的五子棋游戲,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java游戲開發(fā)有一定幫助,需要的可以參考一下
    2022-05-05
  • JavaWeb實(shí)現(xiàn)簡單用戶發(fā)送郵件

    JavaWeb實(shí)現(xiàn)簡單用戶發(fā)送郵件

    這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)簡單用戶發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Spring中@Autowired自動注入map詳解

    Spring中@Autowired自動注入map詳解

    這篇文章主要介紹了Spring中@Autowired自動注入map詳解,  spring是支持基于接口實(shí)現(xiàn)類的直接注入的,支持注入map,list等集合中,不用做其他的配置,直接注入,需要的朋友可以參考下
    2023-10-10
  • java中的DTO的使用示例

    java中的DTO的使用示例

    在Java中,DTO代表數(shù)據(jù)傳輸對象,本文主要介紹了java中的DTO的使用示例,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • JPA與mybatis-plus不兼容問題的解決

    JPA與mybatis-plus不兼容問題的解決

    本文主要介紹了JPA與mybatis-plus不兼容問題的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • Spring Boot 工程的創(chuàng)建和運(yùn)行(圖文)

    Spring Boot 工程的創(chuàng)建和運(yùn)行(圖文)

    這篇文章主要介紹了Spring Boot 工程的創(chuàng)建和運(yùn)行(圖文),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • swing重繪按鈕為任意形狀圖案的方法

    swing重繪按鈕為任意形狀圖案的方法

    這篇文章主要為大家詳細(xì)介紹了swing重繪按鈕為任意形狀圖案,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Java調(diào)用Shell命令和腳本的實(shí)現(xiàn)

    Java調(diào)用Shell命令和腳本的實(shí)現(xiàn)

    這篇文章主要介紹了Java調(diào)用Shell命令和腳本的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02

最新評論

习水县| 留坝县| 湘西| 峨眉山市| 鲁甸县| 崇明县| 巴南区| 喀喇沁旗| 大丰市| 北辰区| 恭城| 台南市| 汝阳县| 牟定县| 临洮县| 香港| 峨眉山市| 郧西县| 黔江区| 樟树市| 怀柔区| 通海县| 镇雄县| 阜南县| 桦甸市| 包头市| 和林格尔县| 北宁市| 喀喇沁旗| 丹凤县| 永城市| 宜丰县| 石嘴山市| 凤冈县| 乡宁县| 黄梅县| 丹凤县| 东阳市| 名山县| 手机| 县级市|