在64位Ubuntu 12.04系统中,一个简单的C程序分配一个大于或等于4GB的动态数组。当程序尝试将值写入数组的每个项目时,会发生段错误。以下是原始代码:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#define ROW 1024 * 1024
#define COL 1024
#define u32 unsigned int
#define u64 unsigned long
int main(int argc, char const *argv[])
{
u32 count = 0;
u64* ary = (u64 *)malloc(sizeof(u32) * ROW * COL);
assert(ary != NULL);
printf("ary:%p\n", ary);
for(u32 r = 0; r < ROW; r++) {
for (u32 c = 0; c < COL; c++) {
ary[r*ROW + c] = count;
count++;
}
}
free(ary);
printf("free array\n");
return 0;
}
将来源编译为:
gcc -o t_32_64_ary_64 t_32_64_ary.c -g -std=c99 -m64
运行时,出现段故障:
ary:0x7fa13584b010
Segmentation fault (core dumped)
由于该机器有16GB内存,所以我相信它分配4GB内存没有任何问题。
如果我将写入值代码注释为:
/*
for(u32 r = 0; r < ROW; r++) {
for (u32 c = 0; c < COL; c++) {
ary[r*ROW + c] = count;
count++;
}
}
*/
该程序正常退出:
ary:0x7f136cd85010
free array
这表明它成功分配了4GB内存。
使用valgrind来运行程序:
valgrind ./t_32_64_ary_64
...
==4830== Warning: set address range perms: large range [0x395a5040, 0x1395a5040) (undefined)
ary:0x395a5040
==4830== Invalid write of size 8
==4830== at 0x4006AE: main (t_32_64_ary.c:21)
==4830== Address 0x1395a5040 is 0 bytes after a block of size 4,294,967,296 alloc'd
==4830== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4830== by 0x400648: main (t_32_64_ary.c:14)
==4830==
==4830==
==4830== Process terminating with default action of signal 11 (SIGSEGV)
==4830== Access not within mapped region at address 0x1395A6000
==4830== at 0x4006AE: main (t_32_64_ary.c:21)
==4830== If you believe this happened as a result of a stack
==4830== overflow in your program's main thread (unlikely but
==4830== possible), you can try to increase the size of the
==4830== main thread stack using the --main-stacksize= flag.
==4830== The main thread stack size used in this run was 8388608.
==4830==
==4830== HEAP SUMMARY:
==4830== in use at exit: 4,294,967,296 bytes in 1 blocks
==4830== total heap usage: 1 allocs, 0 frees, 4,294,967,296 bytes allocated
==4830==
==4830== LEAK SUMMARY:
==4830== definitely lost: 0 bytes in 0 blocks
==4830== indirectly lost: 0 bytes in 0 blocks
==4830== possibly lost: 0 bytes in 0 blocks
==4830== still reachable: 4,294,967,296 bytes in 1 blocks
==4830== suppressed: 0 bytes in 0 blocks
==4830== Rerun with --leak-check=full to see details of leaked memory
==4830==
==4830== For counts of detected and suppressed errors, rerun with: -v
==4830== ERROR SUMMARY: 505 errors from 1 contexts (suppressed: 2 from 2)
Segmentation fault (core dumped)
根据这些信息,似乎是行:
ary[r*ROW + c] = count;
触发段故障,但我不明白为什么。我相信索引:r * RWO + c在数组范围内。
请帮助和谢谢!
答案 0 :(得分:2)
您的索引错误,而您可能无法正确分配。
您可能希望通过malloc(sizeof(u64) * ROW * COL)
进行分配(请注意,我使用的是u64
而不是u32
)。就目前而言,您只需分配一半您可能想要的内存。
您应该按照ary[r*COL + c]
(或ary[c*ROW + r]
进行索引,具体取决于您的需求)。您应该使用size_t
而不是u32
作为索引值,以避免the overflow issues C_Elegans mentions。
此外,虽然这不会导致这个小程序出现问题,但您应养成用括号括起宏定义的习惯(例如#define ROW (1024 * 1024)
)。
答案 1 :(得分:1)
这一行是你的主要问题:
u64* ary = (u64 *)malloc(sizeof(u32) * ROW * COL);
您正在创建指向u64
的指针,但会根据u32
所需的大小计算要分配的大小。
ROW * COL
u64
个unsigned int
号内存分配的内存不足。它可能仅仅是该数字的一半(除非使用对unsigned long
和package timelinefx;
import static javafx.application.Application.launch;
import java.util.Random;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.scene.CacheHint;
public class TextInto3DScene extends Application {
static Stage stage;
static Scene scene;
static Group root;
static Group subSceneRoot;
static PerspectiveCamera camera;
static SubScene subScene;
static boolean cached = true;
static int width = 1000;
static int height = width;
@Override
public void start(Stage primaryStage) throws Exception {
createWindow();
}
protected static void createWindow(){
stage = new Stage();
root = new Group();
root.setCache(cached);
root.setCacheHint(CacheHint.QUALITY); //doesn't work
scene = new Scene(root, 1500, 700, true, SceneAntialiasing.BALANCED);
//Initialize the camera
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(5000);
camera.setTranslateZ(-200);
//creates the SubScene and add the camera to it!
subSceneRoot = new Group();
subSceneRoot.setCache(cached); //doesn't work
subScene = new SubScene(subSceneRoot, 1800, 700, true, SceneAntialiasing.BALANCED);
subScene.setCache(cached);
root.getChildren().add(subScene);
subScene.setFill(Color.WHITE);
subScene.setCamera(camera);
//Create random texts
for( int i = 0;i<=100;++i){
Text text = new Text(Math.random()* width-width/2, Math.random()*height-height/2, randomText() );
text.setFill( Color.BLACK );
text.setTranslateZ( Math.random()*750 );
text.setCache(cached); //doesn't work
text.setCacheHint(CacheHint.QUALITY);
subSceneRoot.getChildren().add(text);
}
stage.setScene(scene);
setEventHandlers();
stage.show();
}
static void setEventHandlers() {
scene.setOnMouseDragged((event) -> {
//camera.setRotate(event.getX());
double translateX = (event.getSceneX() - 0) / stage.getWidth();
translateX = translateX * width - width/2;
double translateY = (event.getSceneY() - 0) / stage.getHeight();
translateY = translateY * height - height/2;
double tz;
if(!camera.getTransforms().isEmpty()){
tz = camera.getTransforms().get(0).getTz();
} else {
tz = camera.getTranslateZ();
}
camera.getTransforms().clear();
camera.getTransforms().addAll( new Translate(translateX, translateY, tz) );
});
//KEY PRESSED
scene.setOnKeyPressed((event) -> {
switch (event.getCode().toString()) {
case "F10":
double amt = event.isControlDown() ? 100 : 30;
camera.setTranslateZ(camera.getTranslateZ() + amt);
break;
case "F11":
amt = event.isControlDown() ? -100 : -30;
camera.setTranslateZ(camera.getTranslateZ() + amt);
break;
}
});
}
static String randomText(){
String out = "";
Random r = new Random();
for(int i = 0;i<=10;++i){
char c = (char) (r.nextInt(26) + 'a');
out += c;
}
return out;
}
public static void main(String[] args) {
launch(args);
}
}
使用相同大小的编译器进行编译)。
编辑:
如其他答案中所述,您的代码存在更多问题。
答案 2 :(得分:1)
使用calloc()
可能是计算所需内存的更优雅的解决方案。我认为这也不容易出错...
#define SIZE 0x40000000 // = 1 GiB
uint32_t *array = (uint32_t *)calloc(SIZE, sizeof(uint32_t));
答案 3 :(得分:0)
malloc
中要分配的字节数的计算是溢出的,因为ROW
和COL
的类型为int
(它们是文字)。要解决此问题,您需要将它们声明为:
#define ROW 1024LL * 1024LL
#define COL 1024LL
或者,考虑使用calloc
,如下所示:
u64* ary = calloc(sizeof(u64) * COL, ROW); //casting malloc is not recommended in C
calloc
在它的参数相乘时检查溢出并始终将它们乘以size_t
,因此乘法将不再溢出