สำหรับจาวามันไม่ได้มีประโยชน์มากนักในการรวมออบเจ็กต์ * เนื่องจากวงจร GC แรกสำหรับวัตถุที่อยู่รอบ ๆ จะสับเปลี่ยนพวกมันในหน่วยความจำย้ายพวกมันออกจากพื้นที่ "Eden" และอาจสูญเสียตำแหน่งเชิงพื้นที่ในกระบวนการ
- มันมีประโยชน์เสมอในภาษาใด ๆ ในการรวมทรัพยากรที่ซับซ้อนซึ่งมีราคาแพงมากในการทำลายและสร้างเช่นเธรด สิ่งเหล่านี้สามารถรวมกำไรได้เนื่องจากค่าใช้จ่ายในการสร้างและทำลายสิ่งเหล่านี้แทบไม่มีส่วนเกี่ยวข้องกับหน่วยความจำที่เกี่ยวข้องกับการจัดการวัตถุกับทรัพยากร อย่างไรก็ตามอนุภาคไม่เหมาะกับหมวดหมู่นี้
Java เสนอการจัดสรรแบบต่อเนื่องอย่างรวดเร็วโดยใช้ตัวจัดสรรแบบต่อเนื่องเมื่อคุณจัดสรรวัตถุในพื้นที่ Eden อย่างรวดเร็ว กลยุทธ์การจัดสรรตามลำดับนั้นเร็วสุดเร็วกว่าmalloc
ใน C เนื่องจากเป็นเพียงการรวมหน่วยความจำที่จัดสรรไว้แล้วตามลำดับแบบต่อเนื่อง แต่มันมาพร้อมกับข้อเสียที่คุณไม่สามารถเพิ่มหน่วยความจำส่วนตัวได้ นอกจากนี้ยังเป็นเคล็ดลับที่มีประโยชน์ใน C หากคุณต้องการจัดสรรสิ่งที่เร็วสุดสำหรับพูดโครงสร้างข้อมูลที่คุณไม่จำเป็นต้องลบอะไรออกจากมันเพียงเพิ่มทุกอย่างแล้วใช้ทุกอย่างแล้วโยนทิ้งทั้งหมดในภายหลัง
เนื่องจากข้อเสียของการไม่สามารถปล่อยวัตถุแต่ละชิ้นได้ดังนั้น Java GC หลังจากรอบแรกจะคัดลอกหน่วยความจำทั้งหมดที่จัดสรรจากพื้นที่ Eden ไปยังพื้นที่หน่วยความจำใหม่โดยใช้ตัวจัดสรรหน่วยความจำวัตถุประสงค์ทั่วไปที่ช้ากว่าและมากขึ้น จะเป็นอิสระในแต่ละชิ้นในหัวข้อที่แตกต่างกัน จากนั้นมันสามารถโยนหน่วยความจำที่จัดสรรในพื้นที่เอเดนโดยรวมโดยไม่ต้องวุ่นวายกับวัตถุแต่ละชิ้นที่ถูกคัดลอกและอยู่ที่อื่นในหน่วยความจำ หลังจากรอบ GC แรกนั้นวัตถุของคุณสามารถจบลงด้วยการแยกส่วนในหน่วยความจำ
เนื่องจากวัตถุสามารถจบลงด้วยการแยกส่วนหลังจากรอบแรกของ GC ประโยชน์ของการรวมวัตถุเมื่อเป็นหลักในการปรับปรุงรูปแบบการเข้าถึงหน่วยความจำ โดยปกติคุณจะได้รับตำแหน่งอ้างอิงที่ดีขึ้นโดยการจัดสรรอนุภาคใหม่ตลอดเวลาและใช้มันในขณะที่ยังคงความสดใหม่ในพื้นที่ Eden และก่อนที่พวกเขาจะกลายเป็น "เก่า" และอาจกระจัดกระจายอยู่ในหน่วยความจำ อย่างไรก็ตามสิ่งที่มีประโยชน์อย่างยิ่ง (เช่นการได้รับประสิทธิภาพเทียบเคียงกับ C ใน Java) คือการหลีกเลี่ยงการใช้วัตถุสำหรับอนุภาคและแหล่งข้อมูลดั้งเดิมแบบธรรมดา สำหรับตัวอย่างง่ายๆแทน:
class Particle
{
public float x;
public float y;
public boolean alive;
}
ทำสิ่งที่ชอบ:
class Particles
{
// X positions of all particles. Resize on demand using
// 'java.util.Arrays.copyOf'. We do not use an ArrayList
// since we want to work directly with contiguously arranged
// primitive types for optimal memory access patterns instead
// of objects managed by GC.
public float x[];
// Y positions of all particles.
public float y[];
// Alive/dead status of all particles.
public bool alive[];
}
ทีนี้เพื่อนำหน่วยความจำสำหรับอนุภาคที่มีอยู่กลับมาใช้ใหม่คุณสามารถทำได้:
class Particles
{
// X positions of all particles.
public float x[];
// Y positions of all particles.
public float y[];
// Alive/dead status of all particles.
public bool alive[];
// Next free position of all particles.
public int next_free[];
// Index to first free particle available to reclaim
// for insertion. A value of -1 means the list is empty.
public int first_free;
}
ตอนนี้เมื่อnth
อนุภาคตายเพื่อให้สามารถนำกลับมาใช้ใหม่ได้ให้กดไปที่รายการอิสระดังนี้:
alive[n] = false;
next_free[n] = first_free;
first_free = n;
เมื่อเพิ่มอนุภาคใหม่ดูว่าคุณสามารถป๊อปดัชนีจากรายการฟรี:
if (first_free != -1)
{
int index = first_free;
// Pop the particle from the free list.
first_free = next_free[first_free];
// Overwrite the particle data:
x[index] = px;
y[index] = py;
alive[index] = true;
next_free[index] = -1;
}
else
{
// If there are no particles in the free list
// to overwrite, add new particle data to the arrays,
// resizing them if needed.
}
มันไม่ใช่รหัสที่น่าพอใจที่สุดที่จะทำงานด้วย แต่ด้วยวิธีนี้คุณควรจะได้รับการจำลองอนุภาคที่รวดเร็วมากด้วยการประมวลผลตามลำดับของอนุภาคที่เป็นมิตรกับแคชมากเสมอเนื่องจากข้อมูลของอนุภาคทั้งหมดจะถูกเก็บไว้อย่างต่อเนื่อง ตัวแทน SoA ประเภทนี้ยังช่วยลดการใช้หน่วยความจำเนื่องจากเราไม่ต้องกังวลเกี่ยวกับการเติมข้อมูลเมตาของวัตถุสำหรับการสะท้อน / การจัดส่งแบบไดนามิกและแยกเขตร้อนออกจากเขตเย็น (ตัวอย่างเช่นเราไม่จำเป็นต้องเกี่ยวข้องกับข้อมูล เขตข้อมูลเช่นสีของอนุภาคในระหว่างที่ฟิสิกส์ผ่านไปดังนั้นมันจึงเป็นเรื่องสิ้นเปลืองที่จะโหลดมันลงในสายแคชเท่านั้นที่จะไม่ใช้มันและขับไล่มัน)
เพื่อให้การทำงานกับโค้ดง่ายขึ้นคุณควรเขียนคอนเทนเนอร์พื้นฐานที่ปรับขนาดได้ของคุณเองซึ่งเก็บอาร์เรย์ของอาร์เรย์อาร์เรย์ของจำนวนเต็มและอาร์เรย์บูลีน คุณไม่สามารถใช้ข้อมูลทั่วไปอีกครั้งและArrayList
ที่นี่ (อย่างน้อยนับตั้งแต่ครั้งสุดท้ายที่ฉันตรวจสอบ) เนื่องจากต้องใช้วัตถุที่มีการจัดการ GC ไม่ใช่ข้อมูลดั้งเดิมที่ต่อเนื่องกัน เราต้องการใช้อาร์เรย์ที่ต่อเนื่องกันint
เช่นไม่ใช่อาร์เรย์ที่มีการจัดการโดย GC Integer
ซึ่งไม่จำเป็นต้องต่อเนื่องกันหลังจากออกจากพื้นที่อีเดน
ด้วยอาร์เรย์ประเภทดั้งเดิมจะรับประกันได้ว่าจะต่อเนื่องกันอยู่เสมอและเพื่อให้คุณได้รับตำแหน่งอ้างอิงที่ต้องการอย่างมาก (สำหรับการประมวลผลตามลำดับทำให้โลกแตกต่าง) และประโยชน์ทั้งหมดที่วัตถุรวมไว้นั้นมีไว้ให้ ด้วยอาเรย์ของวัตถุมันค่อนข้างคล้ายกับอาเรย์ของพอยน์เตอร์ซึ่งเริ่มชี้ไปที่วัตถุในแบบที่ต่อเนื่องกันโดยสมมติว่าคุณจัดสรรพวกมันทั้งหมดในครั้งเดียวในอวกาศ Eden แต่หลังจากรอบ GC สามารถชี้ไปทั่ว วางในหน่วยความจำ