동적 메모리 할당
다름이 아니라, 동적 메모리 할당을 위해 kmalloc을 수행한 후, 정해진 메모리 사이즈보다 더 큰 메모리가 필요할 때마다 krealloc을 통해 추가로 할당해주고 있습니다.
예를 들어,
info = (struct context_info *)kmalloc(_BUFSIZE * sizeof(struct context_info), GFP_KERNEL);
if(context_switched_current >= (alloc_cnt * _BUFSIZE)) {
tmp_info = (struct context_info *)krealloc(info, (alloc_cnt + 1) * _BUFSIZE * sizeof(struct context_info), GFP_KERNEL);
if (!tmp_info) {
kfree(info);
return -ENOMEM;
}
info = tmp_info;
alloc_cnt++;
}
해당 코드를 수행할 때, 다음과 같은 문제점이 있었습니다.
"Unable to handle kernel paging request at virtual address"
처음에 _BUFSIZE를 작게 해서 재할당을 자주하게되면 발생하는 듯 싶습니다.
코드자체에 문제가 있는건지? 아니면, 원래 너무 많은 재할당을 하는건 안좋아서 발생하는건지?
page fault in kernel space
메시지를 보면 커널 주소 공간에서 page fault가 발생한 것 같습니다.
kmalloc으로 할당한 메모리(페이지)는 항상 RAM에 존재할텐데
혹시 해당 함수의 리턴값을 체크하지 않았거나
할당된 영역을 넘어서는 주소를 참조한 것은 아닌지요?
커널 모드에서
커널 모드에서 접근하는 가상 주소가 잘 못된 경우입니다.
의심이 되는 상황은 다음과 같습니다.
1. krealloc()이 실패
2. kfree(info) 수행
3. 다른 곳에서 추가적인 kmalloc() 등이 발생해서 kfree(info)가 해제한 공간 할당
4. 기존 포인터 info 를 통해 계속해서 주소 접근
그나저나 PC는 아닌것 같은데 타겟 프로세서는 무엇인가요?
커널 모드에서
1. krealloc()이 실패
>실패했을 때, 루틴을 통과하지 않습니다.
2. kfree(info) 수행
>이부분은 의심이 되어 빼고 마지막에 kfree(info)를 하였습니다.
3. 다른 곳에서 추가적인 kmalloc() 등이 발생해서 kfree(info)가 해제한 공간 할당
>해제된 공간을 할당하면 문제가 생기나요???
이 점 자세한 설명 부탁드립니다....
4. 기존 포인터 info 를 통해 계속해서 주소 접근
> info = tmp_info; 형태로 하여서 접근하므로 문제가 없는것으로 보입니다.
위에 분이
위에 분이 말씀하신것 처럼 호출자가 해당 함수의 리턴값을 검사하지 않고 info 값을 접근했을 때의 문제점을 풀어 쓴 것입니다.
>해제된 공간을 할당하면 문제가 생기나요??? 이 점 자세한 설명 부탁드립니다....
--> kfree(info)로 해제된 공간은 다음에 ptr = kmalloc() 등이 불리면 다시 할당이 되겠지요.
그러면 같은 공간을 info와 ptr 둘을 이용해서 접근할 수 있다는 의미였습니다.
해당 함수의 리턴값을 검사하셨다면 문제 될 게 없을 듯 합니다.
근데 가능하다면 할당방법을 바꾸는게 좋을 듯 합니다.
kmalloc(), krealloc() 은 물리주소공간상에 연속적인 메모리를 요구하기 때문에 메모리 단편화가 진행되면 큰 메모리 할당은 실패할 가능성이 높습니다.
아래처럼 info를 배열로 잡고 하나씩 잡는게 어떨까요?
info[i] = (struct context_info *)kmalloc(sizeof(struct context_info), GFP_KERNEL);
kmalloc() 대신에 아래 함수를 쓰면 메모리를 좀 더 효율적으로 쓸 수 있습니다.
kmem_cache_create(), kmem_cache_alloc(), kmem_cache_free()
어쩔 수 없이 통으로 메모리를 할당해야 한다면 kmalloc(), krealloc() 대신 vmalloc()을 쓰면 메모리 할당이 실패할 확률이 줄어듭니다.
vmalloc()이 반환하는 메모리는 물리주소공간상에 연속적일 필요없이 가상주소공간상만 연속적이면 되니까요.
또다른 ..사항
아래처럼 info를 배열로 잡고 하나씩 잡는게 어떨까요?
info[i] = (struct context_info *)kmalloc(sizeof(struct context_info), GFP_KERNEL);
-> kmalloc을 수행한 후, 받은 포인터변수 info를 이용해서 접근하기 때문에 배열로 잡게 되면 어려움이 생기네요.
kmalloc() 대신에 아래 함수를 쓰면 메모리를 좀 더 효율적으로 쓸 수 있습니다.
kmem_cache_create(), kmem_cache_alloc(), kmem_cache_free()
-> 이부분은 생각해봐야겠구요.
어쩔 수 없이 통으로 메모리를 할당해야 한다면 kmalloc(), krealloc() 대신 vmalloc()을 쓰면 메모리 할당이 실패할 확률이 줄어듭니다.
vmalloc()이 반환하는 메모리는 물리주소공간상에 연속적일 필요없이 가상주소공간상만 연속적이면 되니까요.
-> 현재 vmalloc으로 바꾸고 재할당할 때, memset을 이용해 copy하고 있습니다. 처음 메모리를 크게 잡아서 재할당을 거의 없게 만들면, 자주 해당 func을 수행해도 문제가 발생하지 않습니다. 하지만, 아주 작은 메모리를 잡고 잦은 재할당을 하게 되면, 같은 문제가 발생하네요...이건 재할당을 자주해서 생기는 문제라고 볼수도 있는건지 궁금합니다. free를 하는데 바로 수행하지 않고 메모리 반납을 하는데 시간이 걸리는 것 같아서요.
댓글 달기