2010-08-19 8 views
13

Estoy intentando averiguar cómo reasignar archivos mapeados en memoria en una Mac (cuando quiero expandir el espacio disponible).¿Realmente no hay mremap en Darwin?

Veo que nuestros amigos en el mundo de Linux tienen mremap pero no puedo encontrar tal función en los encabezados de mi Mac. /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h tiene la siguiente:

  • mmap
  • mprotect
  • msync
  • munlock
  • munmap
  • pero sin mremap

man mremap confirma mis miedos.

Actualmente estoy teniendo que munmap y mmmap si quiero cambiar el tamaño del archivo mapeado, lo que implica la invalidación de todas las páginas cargadas. Debe haber una mejor manera. ¿Seguramente?

Estoy tratando de escribir código que funcione en Mac OS X y Linux. Podría conformarme con una macro para usar la mejor función en cada caso si tuviera, pero preferiría hacerlo correctamente.

Respuesta

0

Puede ftruncionar el archivo a un tamaño grande (creando un agujero) y mmap todo. Si el archivo es persistente, recomiendo llenar el hueco con llamadas de escritura en lugar de escribir en la asignación, ya que de lo contrario los bloques del archivo pueden fragmentarse innecesariamente en el disco.

+0

¿Está sugiriendo que debería asignar el tamaño más grande posible que pueda desear y llenar el agujero? Es una idea interesante, pero o bien mapeo el rango máximo posible de direcciones y no dejo más direcciones para nada más o utilizo una cantidad menor y corro el riesgo de quedarme sin trabajo. Además, esto no sería multiplataforma (como se indicó en mi pregunta) ya que no podía garantizar que algún sistema de archivos no pusiera a cero el rango completo del archivo y desperdiciara gigabytes. – Joe

+3

Ni siquiera necesita convertir el archivo en un disco tan grande. Simplemente 'mmap' es más grande que el tamaño del archivo. Los accesos más allá del final del archivo resultarán en 'SIGBUS', por lo que deberá' ftruncate' más antes de intentar acceder a partes nuevas a través del 'mmap', pero de lo contrario está bien. –

0

No tengo experiencia con la asignación de memoria, pero parece que puede asignar temporalmente el mismo archivo dos veces como medio para expandir la asignación sin perder nada.

int main() { 
    int fd; 
    char *fp, *fp2, *pen; 

     /* create 1K file */ 
    fd = open("mmap_data.txt", O_RDWR | O_CREAT, 0777); 
    lseek(fd, 1000, SEEK_SET); 
    write(fd, "a", 1); 

     /* map and populate it */ 
    fp = mmap(NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
    pen = memset(fp, 'x', 1000); 

     /* expand to 8K and establish overlapping mapping */ 
    lseek(fd, 8000, SEEK_SET); 
    write(fd, "b", 1); 
    fp2 = mmap(NULL, 7000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 

     /* demonstrate that mappings alias */ 
    *fp = 'z'; 
    printf("%c ", *fp2); 

     /* eliminate first mapping */ 
    munmap(fp, 1000); 

     /* populate second mapping */ 
    pen = memset(fp2+10, 'y', 7000); 

     /* wrap up */ 
    munmap(fp2, 7000); 
    close(fd); 
    printf("%d\n", errno); 
} 

La salida es zxxxxxxxxxyyyyyy.....

Supongo que, si consigues esto, es posible que se agote el espacio de direcciones más rápido que con mremap. Pero nada está garantizado de ninguna manera y, por otro lado, podría ser igual de seguro.

+1

Corrígeme si me equivoco, pero ¿esto no causaría mucho IO extra sobre mmap MAP_PRIVATE y mremap? Debido a las escrituras de enjuague MAP_SHARED en el disco? – Eloff

+0

@Eloff: La única forma es intentar y ver. Esta publicación es muy antigua y nunca tuve mucho incentivo para realizar el experimento: vP. Sería un poco sorprendente ver enrojecimientos excesivos, ya que toda la memoria siempre se mapea al menos una vez. El SO solo debe sonrojarse cuando se elimine el último mapeo, ¿verdad? – Potatoswatter

5

Si necesita reducir el tamaño del mapa, solo munmap la pieza al final que desea eliminar.

Si necesita para ampliar el mapa, puede mmap el correcto desplazamiento con MAP_FIXED a las direcciones justo por encima del viejo mapa, pero hay que tener cuidado de que no se asignan sobre otra cosa que es ya allí ..

El texto anterior en ponchado es una idea horrible; MAP_FIXED es fundamentalmente incorrecto a menos que ya sepa lo que está en la dirección de destino y desee reemplazarlo atómicamente. Si intenta mapear de forma oportunista algo nuevo si el rango de direcciones es libre, debe usar mmap con la dirección solicitada pero sinMAP_FIXED y ver si tiene éxito y le da la dirección solicitada; si tiene éxito pero con una dirección diferente, querrá desasignar la nueva asignación que acaba de crear y asumir que la asignación en la dirección solicitada no fue posible.

+0

¿No agrega una región extra mapeada correr el riesgo de no poder asignar en esa dirección? – Joe

+0

Sí, eso es de lo que estaba advirtiendo. Pero creo que 'MAP_FIXED' siempre se asignará sobre una asignación existente (destruyendo la asignación existente) en lugar de fallar, lo que es aún peor. –

1

Si expande en trozos suficientemente grandes (digamos, 64 MB, pero depende de qué tan rápido crezca), entonces el costo de invalidar el mapa antiguo es insignificante. Como siempre, punto de referencia antes de asumir un problema.

Cuestiones relacionadas