C: velocidad de memcpy en arreglos dinámicamente asignados

Necesito ayuda con el rendimiento del siguiente código. Hace un memcpy en dos arreglos asignados dinámicamente de tamaño arbitrario:

int main()
{
  double *a, *b;
  unsigned n = 10000000, i;
  a = malloc(n*sizeof(double));
  b = malloc(n*sizeof(double));
  for(i=0; i<n; i++) {
    a[i] = 1.0;
    /* b[i] = 0.0; */
  }

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero1");

  tic();
  bzero(b, n*sizeof(double));
  toc("bzero2");

  tic();
  memcpy(b, a, n*sizeof(double));
  toc("memcpy");
}

tic / toc mide el tiempo de ejecución.

En mi computadora se necesitan 0.035s para memcpy (Linux, gcc versión 4.4.6). Si ahora descomento la línea que inicializa la matriz de destino b, el código es tres veces más rápido (!) - 0.011s.

He observado un comportamiento similar cuando uso un bucle en lugar de memcpy. Por lo general, no me importa esto, ya que es suficiente para "inicializar" la memoria antes de usarla. Sin embargo, ahora necesito realizar una copia de memoria simple y hacerlo lo más rápido posible. La inicialización de los datos requiere escritura, por ejemplo. 0 a la memoria, que no es necesario y lleva tiempo. Y me gustaría realizar una copia de memoria con todo el ancho de banda de memoria disponible.

¿Hay una solución a este problema? ¿O está conectado a la forma en que Linux maneja la memoria dinámica (¿algún tipo de asignación de página perezosa?) Y no se puede solucionar? ¿Cómo está en otros sistemas?

Editar: Los mismos resultados se obtienen con gcc 4.6. Utilicé -O3 para compilar.

Editar: Gracias a todos por sus comentarios. Entiendo que la asignación de memoria lleva tiempo. Supongo que me cuesta mucho aceptar que demora tanto, mucho más que el acceso a la memoria real. El código se ha modificado para incluir un punto de referencia de la inicialización de la matriz b utilizando dos llamadas bzero posteriores. Los tiempos ahora muestran

bzero1 0.273981
bzero2 0.056803
memcpy 0.117934

Claramente, la primera llamada bero hacemucho más que simplemente transmitir ceros a la memoria, es decir, asignación de memoria y puesta a cero de la memoria. La segunda llamada bzero, por otro lado, toma la mitad del tiempo requerido para hacer un memcpy, que es exactamente lo que se esperaba: escribir solo tiempo frente a leer y escribir tiempo. Entiendo que la sobrecarga de la segunda llamada bero debe estar ahí debido a razones de seguridad del sistema operativo. ¿Qué pasa con el resto? ¿No puedo disminuirlo de alguna manera, por ejemplo? ¿Usar páginas de memoria más grandes? ¿Diferentes configuraciones del kernel?

Debería mencionar que ejecuto esto en sibilancias de Ubuntu.

Respuestas a la pregunta(3)

Su respuesta a la pregunta