TD;DR
我正在将我的一个C++项目移植到android上,但是当使用new
运算符时,它实际上由于某种原因调用了malloc(4294967295)
,这导致了内存不足错误,尽管调试证明我的类大小正确(并且该项目在为Windows构建时可以工作)。
这会导致应用程序在物理Android设备上出现黑屏,或者在模拟器上崩溃
Context
我目前正在尝试将我的SDL项目移植到Android上。
为此,我遵循了the tutorial located in the official SDL repo的说明。此外,我遵循this tutorial将SDL_image模块和SDL_ttf沿着添加到我的项目中。
问题
构建应用程序工作正常,但一旦启动,它就会陷入黑屏:
找出原因(调试)
打印调试
因此,我将手机插入计算机,并尝试使用打印来调试adb
的问题,以下是我发现的:
为了初始化SDL和其他组件,我的游戏的main
函数如下所示:
int main(int argc, char* argv[]) {
__android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Starting");
srand(time(NULL));
const int targetFPS = 60;
const int frameDelay = 1000 / targetFPS;
// Init
__android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Constructing Game class of size: %lX", sizeof(Game));
Game* game = new Game(argc, argv);
__android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Game constructed");
__android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Initializing");
int errInit = game->init("SAE201205", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
__android_log_print(ANDROID_LOG_DEBUG, "DEBUG", "Initialized: %d", errInit);
if (errInit == 0) {
while (game->running()) {
/* Game Logic here */
}
game->clean();
}
delete game;
return 0;
}
注意__android_log_print
调用,它们在这里帮助调试函数。
在手机上启动应用程序并使用adb logcat
捕获手机日志时,可以看到以下几行:
06-14 08:34:35.471 8262 8326 V SDL : Running main function SDL_main from library /data/app/~~F1pn5U_H13LZFzCic5LLyA==/org.libsdl.app-AHd89RMgz8bystTw8XwclA==/lib/arm/libmain.so
06-14 08:34:35.471 8262 8326 V SDL : nativeRunMain()
06-14 08:34:35.471 8262 8326 D DEBUG : Starting
06-14 08:34:35.471 8262 8326 D DEBUG : Constructing Game class of size: 98
06-14 08:34:35.472 8262 8326 W libc : malloc(4294967295) failed: returning null pointer, errno: 12
然后应用程序中断。我写的其他文章从来没有被印刷过。
可以看出,当使用new运算符时,它调用malloc
。问题是,它不是用Game类的大小(0x 98,如上所述)调用它,而是用4294967295(= 0xFFFFFF,如果有符号,则为-1)调用它,因此导致malloc抛出错误12(“内存不足”)。
这是完全没有意义的,因为我显然没有尝试分配4GB的内存,而且由于我的Game类的大小在打印时被编译器正确计算,所以它应该尝试分配正确的大小。
拆解
为了确保确实调用了new运算符,我打开了编译后的.so
文件,其中包含我在Ghidra中的代码。对应于我们感兴趣的指令如下:
可以看出,新操作符确实被调用了。它链接到一个外部函数(因为它是一个共享库构建),但没有错误malloc的痕迹。
但是,传递给新运算符的分配大小似乎是0x108
,而不是打印的0x98
。Ghidra显示的大小可能是正确的,因为Android打印格式似乎存在与此处描述的问题无关的问题(当使用%X
时,编译器警告并要求使用%lX
,但当使用%lX
时,它警告并要求使用%X
)。
我的Windows版本提供了0x130
的大小。我对这种大小差异的理论是,指针大小以及其他本机结构可能不同。
无论哪种方式,无论正确的大小是多少,它都远远不是0xFFFFFFFF
,因此malloc错误不太可能与大小差异有关。
我的配置
下面是我的项目是如何配置的。
首先,它是一个Gradle项目,遵循the same structure as in the official SDL repo:
我的应用程序的Application.mk
文件(here)如下:
# Uncomment this if you're using STL in your project
# You can find more information here:
# https://developer.android.com/ndk/guides/cpp-support
APP_STL := c++_shared
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
# Min runtime API level
APP_PLATFORM=android-16
可以看出,我取消了APP_STL
行的注解,因为我的项目使用了很多STL函数。默认设置为c++_shared
,但我尝试过c++_static
,并面临相同的结果。此外,gnustl_shared
和gnustl_static
已被弃用,无论如何都不适用于SDL项目。
位于同一文件夹(here)中的CMakeLists.txt
文件如下所示:
cmake_minimum_required(VERSION 3.6)
project(GAME)
# armeabi-v7a requires cpufeatures library
# include(AndroidNdkModules)
# android_ndk_import_module_cpufeatures()
# SDL sources are in a subfolder named "SDL"
add_subdirectory(SDL)
# Compilation of companion libraries
add_subdirectory(SDL_image)
#add_subdirectory(SDL_mixer)
add_subdirectory(SDL_ttf)
# Your game and its CMakeLists.txt are in a subfolder named "src"
add_subdirectory(src)
位于我的项目的C++源文件夹(here)中的Android.mk
文件如下所示:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
SDL_PATH := ../SDL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include $(LOCAL_PATH)/../SDL_image/include $(LOCAL_PATH)/../SDL_ttf/include $(LOCAL_PATH)/../include
# Add your application source files here...
LOCAL_SRC_FILES := main.cpp <all my other cpp files here, irrelevant so not including them>
LOCAL_SHARED_LIBRARIES := SDL2 SDL2_image SDL2_ttf
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroid
include $(BUILD_SHARED_LIBRARY)
我没有编辑任何其他配置文件,据我所知(和检查)。如果您需要我没有在这里包含的特定文件的内容,请随时询问。
我现在在哪里
这类问题是如此具体,它是很难找到任何人谁遇到任何错误接近这一点,所以我没有发现任何东西
作为提醒,该项目编译和适用于Windows,我在这里遇到的问题是Android独占。
如果我可以理论化的话,我会说c++库只是有一个选项,我错过了支持new
操作符,但我找不到任何东西,而且我对android开发非常陌生,所以我不能肯定。
1条答案
按热度按时间yptwkmov1#
我发现问题了。
正如评论者所指出的那样,Game类的构造函数出了问题,而不是内存分配本身。
我以为我已经删除了所有可能导致崩溃的东西,但那是在不知道类的成员即使没有明确说明也会被构造的情况下,这导致了崩溃,因为其中一些人以Windows的方式请求文件。
对不起!