免费观看又色又爽又黄的小说免费_美女福利视频国产片_亚洲欧美精品_美国一级大黄大色毛片

幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

在公司有一個(gè)需求是要核對(duì)一批數(shù)據(jù),之前的做法是直接用SQL各種復(fù)雜操作給懟出來(lái)的,不僅時(shí)間慢,而且后期也不好維護(hù),就算原作者來(lái)了過(guò)一個(gè)月估計(jì)也忘了SQL什么意思了,于是有一次我就想著問(wèn)一下之前做這個(gè)需求的人為什么不將這些數(shù)據(jù)查出來(lái)后在內(nèi)存里面做篩選呢?直接說(shuō)了你不怕把內(nèi)存給撐爆嗎?此核算服務(wù)器是單獨(dú)的服務(wù)器,配置是四核八G的,配置堆的大小是4G。本著懷疑的精神,就想要弄清楚幾百萬(wàn)條數(shù)據(jù)真的放入內(nèi)存的話會(huì)占用多少內(nèi)存呢?

成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括海州網(wǎng)站建設(shè)、海州網(wǎng)站制作、海州網(wǎng)頁(yè)制作以及海州網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,海州網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到海州省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

計(jì)算機(jī)的存儲(chǔ)單位
計(jì)算機(jī)的存儲(chǔ)單位常用的有bit、Byte、KB、MB、GB、TB后面還有但是我們基本上用不上就不說(shuō)了,我們經(jīng)常將bit稱之為比特或者位、將Byte簡(jiǎn)稱為B或者字節(jié),將KB簡(jiǎn)稱為K,將MB稱之為M或者兆,將GB簡(jiǎn)稱為G。那么他們的換算單位是怎樣的呢?

換算關(guān)系
首先我們得知道在計(jì)算機(jī)中所有數(shù)據(jù)都是由0 1來(lái)組成的,那么存儲(chǔ)0 1這些二進(jìn)制數(shù)據(jù)是由什么存放呢?就是由bit存放的,一個(gè)bit存放一位二進(jìn)制數(shù)字。所以bit是計(jì)算機(jī)最小的單位。

大部分計(jì)算機(jī)目前都是使用8位的塊,就是我們上面稱之為的字節(jié)Byte,來(lái)作為計(jì)算機(jī)容量的基本單位。所以我們一般稱一個(gè)字符或者一個(gè)數(shù)字都是稱之為占用了多少字節(jié)。

了解了上面關(guān)于位和字節(jié)的關(guān)系后,我們可以看一下其他的單位換算關(guān)系

11B(Byte 字節(jié)) = 8bit(位)
21KB = 1024B
31MB = 1024KB
41GB = 1024MB
51TB = 1024GB

Java中對(duì)象占用多少內(nèi)存
在了解了上面的換算關(guān)系后,我們來(lái)了解一下新建一個(gè)Java對(duì)象需要多少內(nèi)存。

Java基本類型
我們知道Java類型分為基本類型和引用類型,八大基本類型有int、short、long、byte、float、double、boolean、char
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

至于為什么Java中的char無(wú)論是中英文數(shù)字都占用兩個(gè)字節(jié),是因?yàn)镴ava中使用Unicode字符,所有的字符均以兩個(gè)字節(jié)存儲(chǔ)。

Java引用類型
在一個(gè)對(duì)象中除了有基本數(shù)據(jù)類型以外,我們也會(huì)有一些引用類型,引用類型的對(duì)象比較特殊,因?yàn)檫@些對(duì)象真正存儲(chǔ)在虛擬機(jī)中的堆內(nèi)存中,對(duì)象中只是存儲(chǔ)了一個(gè)引用而已,如果是引用類型那么就會(huì)存儲(chǔ)一個(gè)指向該引用的指針。指針默認(rèn)情況下是占用4字節(jié),是因?yàn)殚_(kāi)啟了指針壓縮,如果沒(méi)有開(kāi)的話,那么一個(gè)引用就占用8個(gè)字節(jié)。

對(duì)象在內(nèi)存中的布局
在HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為三個(gè)區(qū)域:對(duì)象頭(Header)、實(shí)例數(shù)據(jù)(Instance Data)、對(duì)齊填充(Padding)。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

對(duì)象頭

在對(duì)象頭中存儲(chǔ)了兩部分?jǐn)?shù)據(jù)

運(yùn)行時(shí)數(shù)據(jù):存儲(chǔ)了對(duì)象自身運(yùn)行時(shí)的數(shù)據(jù),例如哈希碼、GC分代的年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID等等。這部分?jǐn)?shù)據(jù)在32位和64位的虛擬機(jī)中分別為32bit和64bit
類型指針:對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例。如果對(duì)象是一個(gè)Java數(shù)組的話,那么對(duì)象頭中還必須有一塊用于記錄數(shù)組長(zhǎng)度的數(shù)據(jù)(占用4個(gè)字節(jié))。所以這是一個(gè)指針,默認(rèn)JVM對(duì)指針進(jìn)行了壓縮,用4個(gè)字節(jié)存儲(chǔ)。
我們以虛擬機(jī)為64位的機(jī)器為例,那么對(duì)象頭占用的內(nèi)存是8(運(yùn)行時(shí)數(shù)據(jù))+4(類型指針)=12Byte。如果是數(shù)組的話那么就是16Byte

實(shí)例數(shù)據(jù)

實(shí)例數(shù)據(jù)中也擁有兩部分?jǐn)?shù)據(jù),一部分是基本類型數(shù)據(jù),一部分是引用指針。這兩部分?jǐn)?shù)據(jù)我們?cè)谏厦嬉呀?jīng)講了。具體占用多少內(nèi)存我們需要結(jié)合具體的對(duì)象繼續(xù)分析,下面我們會(huì)有具體的分析。

從父類中繼承下來(lái)的變量也是需要進(jìn)行計(jì)算的

對(duì)齊填充

對(duì)齊填充并不是必然存在的,也沒(méi)有特別的含義。它僅僅起著占位符的作用。由于HotSpot VM的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象起始地址必須是8字節(jié)的整數(shù)倍,換句話說(shuō)就是對(duì)象的大小必須是8字節(jié)的整數(shù)倍。而如果對(duì)象頭加上實(shí)例數(shù)據(jù)不是8的整數(shù)倍的話那么就會(huì)通過(guò)對(duì)其填充進(jìn)行補(bǔ)全。

實(shí)戰(zhàn)演練

我們?cè)谏厦娣治鲆淮蠖眩敲词遣皇蔷腿缥覀兎治龅囊粯樱陆ㄒ粋€(gè)對(duì)象在內(nèi)存中的分配大小就是如此呢?我們可以新建一個(gè)對(duì)象。

lass Animal{

   private int age;

}

那么怎么知道這個(gè)對(duì)象在內(nèi)存中占用多少內(nèi)存呢?JDK提供了一個(gè)工具jol-core可以給我們分析出來(lái)一個(gè)對(duì)象在內(nèi)存中占用的內(nèi)存大小。直接在項(xiàng)目中引入包即可。

--Gradle
compile 'org.openjdk.jol:jol-core:0.9'

--Maven
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

然后我們?cè)趍ain函數(shù)中調(diào)用如下

public class AboutObjectMemory {

    public static void main(String[] args) {
        System.out.print(ClassLayout.parseClass(Animal.class).toPrintable());
    }
}

就可以查看到輸出的內(nèi)容了,可以看到輸出結(jié)果占用的內(nèi)存是16字節(jié),和我們分析的一樣。

aboutjava.other.Animal object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    12        (object header)                           N/A
     12     4    int Animal.age                                N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

String占用多少內(nèi)存
String字符串在Java中是個(gè)特殊的存在,比如一個(gè)字符串"abcdefg"這樣一個(gè)字符串占用多少字節(jié)呢?相信會(huì)有人回答說(shuō)是7個(gè)字節(jié)或者是14個(gè)字節(jié),這兩個(gè)答案都是不準(zhǔn)確的,我們先看一下String類在內(nèi)存中占用的內(nèi)存是多少。
我們先自己進(jìn)行分析一下。在String類中有兩個(gè)屬性,其中對(duì)象頭固定了是12字節(jié),int是4字節(jié),char[]數(shù)組其實(shí)在這里相當(dāng)于引用對(duì)象存的,所以存的是地址,因此占用4個(gè)字節(jié),所以大小為對(duì)象頭12Byte+實(shí)例數(shù)據(jù)8Byte+填充數(shù)據(jù)4Byte=24Byte這里的對(duì)象頭和實(shí)例數(shù)據(jù)加起來(lái)不是8的倍數(shù),所以需要填充數(shù)據(jù)進(jìn)行填充。

private final char value[];

private int hash; // Default to 0

那么我們分析的到底對(duì)不對(duì)呢,我們還是用上面的工具進(jìn)行分析一下。可以看到我們算出的結(jié)果和我們分析的結(jié)果是一致的。

java.lang.String object internals:
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0    12          (object header)                           N/A
     12     4   char[] String.value                              N/A
     16     4      int String.hash                               N/A
     20     4          (loss due to the next object alignment)
Instance size: 24 bytes

那么一個(gè)空字符串占用多少內(nèi)存呢?我們剛才得到的是一個(gè)String對(duì)象占用了24字節(jié),其實(shí)char[]數(shù)組還是會(huì)占用內(nèi)存的,我們?cè)谏厦嬷v對(duì)象頭的時(shí)候說(shuō)過(guò),數(shù)組對(duì)象也是一個(gè)實(shí)例對(duì)象,它的對(duì)象頭比一般的對(duì)象多出來(lái)4字節(jié),用來(lái)描述此數(shù)組的長(zhǎng)度,所以char[]數(shù)組的對(duì)象頭長(zhǎng)度為16字節(jié),由于此時(shí)是空字符串,所以實(shí)例數(shù)據(jù)長(zhǎng)度為0。因此一個(gè)空char[]數(shù)組占用內(nèi)存大小為對(duì)象頭16Byte+實(shí)例數(shù)據(jù)0Byte=16Byte。一個(gè)空字符串占用內(nèi)存為String對(duì)象+char[]數(shù)組對(duì)象=40Byte

那么我們上面舉的例子abcdefg占用多少內(nèi)存呢?其中String對(duì)象占用的內(nèi)存是不會(huì)變了,變化的是char[]數(shù)組中的內(nèi)容,這里我們需要知道字符串是存放于char[]數(shù)組中的,而一個(gè)char占用2個(gè)字節(jié),所以abcdefg的char[]數(shù)組大小為對(duì)象頭16Byte+實(shí)例數(shù)據(jù)14Byte+對(duì)齊填充2Byte=32Byte。那么abcdefg占用內(nèi)存大小就是String對(duì)象+char[]數(shù)組對(duì)象=56Byte

用List存儲(chǔ)對(duì)象
那么我們?cè)趦?nèi)存中放入二千萬(wàn)個(gè)這個(gè)對(duì)象的話,需要占用多少內(nèi)存呢?根據(jù)上面的知識(shí)我們能大概估算一下。我們定義一個(gè)List數(shù)組用于存放此對(duì)象,不讓其回收。

List<Animal> animals = new ArrayList<>(20000000);
for (int i = 0; i < 20000000; i++) {
    Animal animal = new Animal();
    animals.add(animal);
}

注意這里我是直接將集合的大小初始化為了二千萬(wàn)的大小,所以程序在正常啟動(dòng)的時(shí)候占用內(nèi)存是100+MB,正常程序啟動(dòng)僅僅占用30+MB的,所以多出來(lái)的60+MB正好是我們初始化的數(shù)組的大小。至于為什么要初始化大小的原因就是為了消除集合在擴(kuò)容時(shí)對(duì)我們觀察結(jié)果的影響

這里我貼一張,集合未初始化大小和初始化大小內(nèi)存占用對(duì)比圖,大家可以看到是有內(nèi)存上的差異,在ArrayList數(shù)組中用于存放數(shù)據(jù)的是transient Object[] elementData;Object數(shù)組,所以它里面存放的是指向?qū)ο蟮闹羔槪粋€(gè)指針占用4個(gè)字節(jié),所以就有兩千萬(wàn)個(gè)指針,那么就是76M。我們可以看到差異圖和我們預(yù)想的一樣。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

上面我們已經(jīng)算出來(lái)了一個(gè)Animal對(duì)象占用16個(gè)字節(jié),所以兩千萬(wàn)個(gè)占用大概是305MB,和集合加起來(lái)就是將近380MB的空間大小,接下來(lái)我們就啟動(dòng)程序來(lái)看一下我們結(jié)果是不是對(duì)的呢,接下來(lái)我用的jconsole工具查看內(nèi)存占用情況。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

我們可以看到和我們預(yù)算的結(jié)果是相吻合的。

那么以后如果有大量的對(duì)象需要從數(shù)據(jù)庫(kù)中查找出來(lái)放入內(nèi)存的話,那么如果是使用對(duì)象來(lái)接的話,那么我們就應(yīng)該盡量減少對(duì)象中的字段,因?yàn)榧词鼓悴毁x值,其實(shí)他也是占用著內(nèi)存的,我們接下來(lái)再舉個(gè)例子看一下對(duì)個(gè)屬性值的話占用內(nèi)存是不是又高了。我們將Animal對(duì)象改造如下

class Animal{

    private int age;
    private int age1;
    private int age2;
    private int age3;
    private int age4;

}

此時(shí)我們能夠計(jì)算得到一個(gè)Animal對(duì)象占用的內(nèi)存大小是(對(duì)象頭12Byte+實(shí)例數(shù)據(jù)20Byte=32Byte)此時(shí)32由于是8的倍數(shù)所以無(wú)需進(jìn)行填充補(bǔ)齊。那么此時(shí)如果還是二千萬(wàn)條數(shù)據(jù)的話,此對(duì)象占用內(nèi)存應(yīng)該是610MB,加上剛才集合中指針的數(shù)據(jù)76MB,那么加起來(lái)將近占用686MB,那么預(yù)期結(jié)果是否和我們的一樣呢,我們重新啟動(dòng)程序觀察,可以看到下圖。可以看到和我們分析的數(shù)據(jù)是差不多的。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

用Map存儲(chǔ)對(duì)象
用Map存儲(chǔ)對(duì)象計(jì)算內(nèi)存大小有些麻煩了,眾所周知Map的結(jié)構(gòu)是如下圖所示。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

它是一個(gè)數(shù)組加鏈表(或者紅黑樹(shù))的結(jié)構(gòu),而數(shù)組中存放的數(shù)據(jù)是Node對(duì)象。

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
}

我們舉例定義下面一個(gè)Map對(duì)象

Map<Animal,Animal> map

此時(shí)我們可以自己計(jì)算一下一個(gè)Node對(duì)象需要的內(nèi)存大小對(duì)象頭12Byte+實(shí)例數(shù)據(jù)16Byte+對(duì)其填充4Byte=32Byte,當(dāng)然這里的key和value的值還需要另算,因?yàn)镹ode對(duì)象此時(shí)存放的僅僅是他們的引用而已。一個(gè)Animal對(duì)象所占用內(nèi)存大小我們上面也說(shuō)了是16Byte,所以這里一個(gè)Node對(duì)象占用的大小為32Byte+16Byte+16Byte=64Byte。

下面我們用實(shí)際例子來(lái)驗(yàn)證下我們的猜想

Map<Animal,Animal> map = new HashMap<>(20000000);
for (int i = 0; i < 20000000; i++) {
    map.put(new Animal(),new Animal());
}

上面的例子在一個(gè)Map對(duì)象中存放二千萬(wàn)條數(shù)據(jù),計(jì)算大概在內(nèi)存中占用多少內(nèi)存。

數(shù)組占用內(nèi)存大小:我們先來(lái)計(jì)算一下數(shù)組占了多少,這里有個(gè)小知識(shí)點(diǎn),在HashMap中初始化大小是按照2的倍數(shù)來(lái)的,比如你定義了大小為60,那么系統(tǒng)會(huì)給你初始化大小為64。所以我們定義為二千萬(wàn),系統(tǒng)其實(shí)是會(huì)給我們初始化為33554432,所以此時(shí)僅僅HashMap中數(shù)組就占用了將近132MB
數(shù)據(jù)占用內(nèi)存大小:我們上面計(jì)算了一個(gè)Node節(jié)點(diǎn)占用了64Byte,那么兩千萬(wàn)條數(shù)據(jù)就占用了1280MB
兩個(gè)占用內(nèi)存大小相加我們可以知道大概系統(tǒng)中占用了1.4G內(nèi)存的大小。那么事實(shí)是否是我們想象的呢?我們運(yùn)行程序可以看到內(nèi)存大小如圖所示。可以看到結(jié)果確實(shí)和我們猜想的一樣。
幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?

總結(jié)
回歸到上面所說(shuō)的需求,幾百萬(wàn)數(shù)據(jù)放到內(nèi)存中會(huì)把內(nèi)存撐爆嗎?這時(shí)候你可以通過(guò)自己的計(jì)算得到。最終我們那個(gè)需求經(jīng)過(guò)我算出來(lái)其實(shí)占用內(nèi)存量幾百兆,對(duì)于4個(gè)G的堆內(nèi)存來(lái)說(shuō)其實(shí)遠(yuǎn)遠(yuǎn)還沒(méi)達(dá)到撐爆的地步。所以有時(shí)候我們對(duì)任何東西都要存在懷疑的態(tài)度。大家可以到GitHub中下載代碼自己在本地跑一下監(jiān)測(cè)一下,并且可以自己定義幾個(gè)對(duì)象然后計(jì)算看是不是和圖中的內(nèi)存大小一致。這樣才能記憶更深刻。送給大家一句話從來(lái)如此,便對(duì)嗎?。其實(shí)我寫(xiě)的文章里面也留了一個(gè)小坑,大家可以試著找找,是在對(duì)集合進(jìn)行初始化計(jì)算那一塊。

分享題目:幾百萬(wàn)數(shù)據(jù)放入內(nèi)存不會(huì)把系統(tǒng)撐爆嗎?
分享鏈接:http://m.newbst.com/article30/gciepo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設(shè)外貿(mào)建站移動(dòng)網(wǎng)站建設(shè)響應(yīng)式網(wǎng)站品牌網(wǎng)站建設(shè)建站公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化