He querido escribir una publicación sobre el trabajo con la memoria virtual desde hace bastante tiempo . Y cuando @jimsagevid en respuesta a mi tweet escribió al respecto, me di cuenta de que había llegado el momento.
— . , , ( , ), . , - , . , ( ) - .
, , .
, , , . , , . , - std::vector , .
:
objecto *objects[MAXOBJECTS]
? , . — . , , @jimsagevid, .
. , .
, . , 1 :
#define MAXOBJECTS 1000000000ULL
objecto **objects = virtualalloc(MAXOBJECTS * sizeof(objecto ));
8 , , . , .
— virtualalloc()
, . Windows VirtualAlloc(), Linux mmap().
— Windows MEMRESERVE MEMCOMMIT. MEMRESERVE , MEMCOMMIT . , MEMCOMMIT, , . MEMCOMMIT , , , MEMCOMMIT . Windows , , MEMCOMMIT ( ). MEMRESERVE , MEMCOMMIT .
, Linux overcommit ( ). , . Linux (reserve) (commit), .
8 ? . — . 64- 2⁶⁴. , . . . , 64- Windows 256 . 32 000 8 , , .
, , - .
:
uint32_t num_tanks;
tank_t tanks[MAX_TANKS];
uint32_t num_bullets;
bullet_t bullets[MAX_BULLETS];
...
, , , , . , std::vector
MAX¨C13C 1 :
#define GB 1000000000
uint32_t num_tanks;
tank_t *tanks = virtual_alloc(GB);
uint32_t num_bullets;
bullet_t *bullets = virtual_alloc(GB);
ID
(ID) . :
uint64_t allocate_id(system_t *sys)
{
return sys->next_free_id++;
}
. , . , . , , .
:
system_id_t *allocate_id(system_t *sys)
{
if (!sys->id_block || sys->id_block_used == PAGE_SIZE) {
sys->id_block = virtual_alloc(PAGE_SIZE);
sys->id_block_used = 0;
}
return (system_id_t *)(sys->id_block + sys->id_block_used++);
}
, , (opaque struct), , uint64_t
.
— , - , . - , , , . , , , , . , .
, , " " . . 64- , , 2 , 99,999999988%. , , , , , / . , , .
, , . :
, .
.
, - , . , , - . , , (allocation block header).
, end-of-page — ( ). , .
. -, , . , . , — , , .
-, , . , "" , .
, . , , , end-of-page — . . , .
end-of-page . malloc
:
void *eop_malloc(uint64_t size)
{
uint64_t pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
char *base = virtual_alloc(pages * PAGE_SIZE);
uint64_t offset = pages * PAGE_SIZE - size;
return base + offset;
}
— . , . , , , .
. (reserved), (commited). , , . , . (access violation). (: Windows, reserve commit .)
. end-of-page — .
. , , .
, , , "" . , , . , , . . , - .
— . , .
, . "" , "" , .
, . . -, , .
, . .. , . , , , , , 99.999999988% . . ( 32- .)
, , 4 . , — , .
. — , .
. , , . , 300 . , , . , 16 32 64 128 . , .
16 * 300 = 4800. 8 , . . , : 4 , 8 , 16 , 32 , …, , (13, 27, 54, 109,…). - , 150 2 .
, . , , , , .
? . , . , , TLB. , , , — , — --. , - .
, . . , . , — 32- — 64- 4K .
. , .
"" "" , , , . uint64t, , - :
enum {BUFFER_SIZE = 8*1024};
struct ring_buffer_t {
uint8_t data[BUFFER_SIZE];
uint64_t read;
uint64_t written;
};
, , , , . , BUFFER_SIZE
, . , . , .
, , . , memcpy
, .
void write(ring_buffer_t *rb, uint8_t *p, uint64_t n)
{
uint64_t offset = rb->written % BUFFER_SIZE;
uint64_t space = BUFFER_SIZE - offset;
uint64_t first_write = n < space ? n : space;
memcpy(rb->data + offset, p, first_write);
memcpy(rb->data, p + first_write, n - first_write);
rb->written += n;
}
, . , — . memcpy()
.
? " " (commit) , (decommit). — , . . , . 1 / 4 () . , , 64- Windows 256 . , commit decommit .
, , . . . , (ring buffer), .
, " " . , . :
void write(ring_buffer_t *rb, uint8_t *p, uint64_t n)
{
memcpy(rb->data + (rb->written % BUFFER_SIZE), p, n);
rb->written += n;
}
uint8_t *read(ring_buffer_t *rb, uint64_t n)
{
uint8_t *p = rb->data + (rb->read % BUFFER_SIZE);
rb->read += n;
return p;
}
, - .
, . Windows CreateFileMapping()
. , , " ", . , INVALID_HANDLE_VALUE
, . MapViewOfFileEx()
, . , , . , MapViewOfFileEx()
, , , , - - . , , . , .
- , , @niklasfrykholm.
Linux
, "Linux overcommit ( )". , , , , , .
Linux "" commit ( ). overcommit, , . , overcommit, , , , , . OOM killer .
, overcommit (vm.overcommit_memory = 1
) (vm.overcommit_memory = 2
). . https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
, . , .
, Windows: (reserve) (commit). overcommit_memory
.
mmap()
, Linux mmap()
PROT_NONE
. commit , mprotect()
.
— MAP_NORESERVE
PROT_NONE
, overcommit_memory = 2
, MAP_NORESERVE
. . https://lwn.net/Articles/627557/
" ".