Las palabras clave no son fáciles, indique la fuente para la reimpresión
https://blog.csdn.net/newchenxf/article/details/121537539
1 Conclusión
Tal vez abriste este artículo tarde en la noche cuando estabas trabajando horas extras. Realmente no tienes mucho tiempo y realmente quieres irte a casa, así que no puedo empezar con un montón de tonterías. Esta vez, hagamos una conclusión primero como referencia, si es inútil, date prisa y encuentra otra...
Aparece SIGSEGV
, sí 进程执行了一个无效的内存引用
. Actualmente estoy experimentando dos bloqueos por diferentes motivos, que se enumeran aquí.
razón:
对象在使用时已被释放。
对象没有初始化。
Para ampliar un poco más:
对象A用局部变量初始化,分配在栈上,函数结束就提前释放了。赋值给其他对象B,B在其他函数引用A时,出现崩溃。
对象没有被初始化,判空又不为空,使用时崩溃。
Solución:
使用智能指针,或者A改成全局变量。
保证变量在使用前初始化,例如在构造函数初始化。
Ok, a continuación, hablemos de ello en detalle.
2 casos en que un objeto ha sido liberado mientras estaba en uso
2.1 Antecedentes del problema
Después de escribir el código C++ de Android, se bloquea cuando se ejecuta y el registro es el siguiente:
11-25 15:07:25.546 24467 24527 E glesdemo: ReadMissingBones, m_BoneInfoMap address 0x7e70ed0f88, size 52
11-25 15:07:25.554 24467 24527 E glesdemo: GetBoneIDMap, m_BoneInfoMap size 0
11-25 15:07:25.654 24718 24718 I crash_dump64: performing dump of process 24467 (target tid = 24527)
11-25 15:07:25.655 24718 24718 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-25 15:07:25.655 24718 24718 F DEBUG : Build fingerprint: 'Xiaomi/sagit/sagit:8.0.0/OPR1.170623.027/V10.2.1.0.OCACNFK:user/release-keys'
11-25 15:07:25.655 24718 24718 F DEBUG : Revision: '0'
11-25 15:07:25.655 24718 24718 F DEBUG : ABI: 'arm64'
11-25 15:07:25.655 24718 24718 F DEBUG : pid: 24467, tid: 24527, name: GLThread 6769 >>> com.chenxf.opengles <<<
11-25 15:07:25.655 24718 24718 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x23d70a00000020
11-25 15:07:25.655 24718 24718 F DEBUG : x0 3c23d70a00000020 x1 0000007e70ed0ce0 x2 0000000000000018 x3 3c23d70a00000020
11-25 15:07:25.655 24718 24718 F DEBUG : x4 0000007e72355438 x5 0000007e70ed0f68 x6 0000007e70ed11a0 x7 0000000000000000
11-25 15:07:25.655 24718 24718 F DEBUG : x8 0000007e72355420 x9 3c23d70a00000020 x10 0000007e70ed0e98 x11 0000007e70ed11a0
11-25 15:07:25.655 24718 24718 F DEBUG : x12 0000007e71a44808 x13 0000000000000001 x14 ffffffffffffffff x15 26204f3d44495400
11-25 15:07:25.656 24718 24718 F DEBUG : x16 0000007e72bbbac0 x17 0000007e72b828bc x18 0000000000000001 x19 0000007e7efa5400
11-25 15:07:25.656 24718 24718 F DEBUG : x20 0000007e72b70ee4 x21 000000001384f730 x22 000000001384b8f0 x23 0000007e8f90ab47
11-25 15:07:25.656 24718 24718 F DEBUG : x24 0000000000000008 x25 0000007e7efa5498 x26 0000000000000000 x27 0000000000000000
11-25 15:07:25.656 24718 24718 F DEBUG : x28 0000000000000002 x29 0000007e70ed0c80 x30 0000007e72b79bfc
11-25 15:07:25.656 24718 24718 F DEBUG : sp 0000007e70ed0c70 pc 0000007e72b79bfc pstate 0000000020000000
11-25 15:07:25.661 24718 24718 F DEBUG :
11-25 15:07:25.661 24718 24718 F DEBUG : backtrace:
11-25 15:07:25.661 24718 24718 F DEBUG : #00 pc 0000000000028bfc /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG : #01 pc 0000000000031780 /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG : #02 pc 000000000003e1ec /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG : #03 pc 000000000003e1b8 /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG : #04 pc 000000000003e16c /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
11-25 15:07:25.661 24718 24718 F DEBUG : #05 pc 000000000003e110 /data/app/com.chenxf.opengles-bU4sOnN8Yuev-eQs6nf7QA==/base.apk (offset 0x1606000)
No hay información de pila de eso en absoluto. No sé qué línea en absoluto, ¿cuál podría ser la razón de esto?
Primero enumero el código dependiente de la siguiente manera:
El animador de primera clase:
class Animator
{
public:
Animator(Animation* animation)
{
m_CurrentAnimation = animation;
}
void CalculateBoneTransform()
{
//省略代码...
std::map<std::string,BoneInfo> boneInfoMap = m_CurrentAnimation->GetBoneIDMap();
DEBUG_LOGCATE();
if (boneInfoMap.find(nodeName) != boneInfoMap.end())
{
DEBUG_LOGCATE();
//省略代码...
}
}
private:
Animation* m_CurrentAnimation;
};
La animación de segunda clase
class Animation
{
public:
Animation() = default;
Animation(const std::string& animationPath, ModelAnim* model)
{
m_BoneInfoMap = model.GetBoneInfoMap();//getting m_BoneInfoMap from Model class
LOGCATE("ReadMissingBones, m_BoneInfoMap address %p, size %d", &m_BoneInfoMap,m_BoneInfoMap.size());
}
~Animation()
{
}
inline const std::map<std::string,BoneInfo>& GetBoneIDMap()
{
LOGCATE("GetBoneIDMap, m_BoneInfoMap size %d", m_BoneInfoMap.size());
return m_BoneInfoMap;
}
private:
std::map<std::string, BoneInfo> m_BoneInfoMap;
};
La tercera clase inicializa las 2 clases anteriores y usa:
void Model3DAnimSample::Init() {
Animation animation(path + "/model/vampire/dancing_vampire.dae", m_pModel);
m_pAnimator = new Animator(&animation);
//...
}
void Model3DAnimSample::Draw(int screenW, int screenH) {
m_pAnimator->CalculateBoneTransform();
//省略...
}
2.2 Análisis de causas
Puedo reproducir localmente, así que agregué muchos registros para rastrear, vea las dos primeras líneas del registro superior:
11-25 15:07:25.546 24467 24527 E glesdemo: ReadMissingBones, m_BoneInfoMap address 0x7e70ed0f88, size 52
11-25 15:07:25.554 24467 24527 E glesdemo: GetBoneIDMap, m_BoneInfoMap size 0
Este m_BoneInfoMap tiene 52 cuando se le asigna un valor. Cuando lo llama la función CalculateBoneTransform de Animator, lee el valor y se convierte en 0. Si se usa más, fallará.
¿por qué? ¡Después de leer durante mucho tiempo, m_BoneInfoMap no se ha modificado en ningún otro lugar! ! !
Veamos de nuevo la información de la pila:
11-25 15:07:25.655 24718 24718 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x23d70a00000020
¿Qué significan estos 2 caracteres?
SIGSEGV
: El proceso ejecutó una referencia de memoria no válida.
SEGV_MAPERR
: Indica un error de mapa de pila.
Entonces salió la razón:
在Init函数,animation是局部变量,栈上分配的,再赋值给m_pAnimator。 Init函数结束后,animation就无效了,后面m_pAnimator再使用animation,就是栈上的脏数据,所以出现了SIGSEGV
2.3 Soluciones
- Haz de Animation una variable global de la clase. Ahora mismo
m_pAnimation = new Animation(path + "/model/vampire/dancing_vampire.dae", m_pModel);
m_pAnimator = new Animator(m_pAnimation);
- Use punteros inteligentes para crear animaciones, a saber, share_ptr. Para punteros inteligentes, consulte: https://blog.csdn.net/newchenxf/article/details/116019535
3 Caso 2 El objeto no se inicializa
3.1 Antecedentes del problema
Misma pila que el Caso 1
12-27 16:06:13.513 20962 20962 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
12-27 16:06:13.513 20962 20962 F DEBUG : Build fingerprint: 'Xiaomi/sagit/sagit:8.0.0/OPR1.170623.027/V10.2.1.0.OCACNFK:user/release-keys'
12-27 16:06:13.513 20962 20962 F DEBUG : Revision: '0'
12-27 16:06:13.513 20962 20962 F DEBUG : ABI: 'arm64'
12-27 16:06:13.513 20962 20962 F DEBUG : pid: 20871, tid: 20905, name: GLThread 7653 >>> com.chenxf.opengles <<<
12-27 16:06:13.513 20962 20962 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x72006500640069
12-27 16:06:13.513 20962 20962 F DEBUG : x0 0072006500640069 x1 0000000000000302 x2 00000000ffffffff x3 0000007196a37e0c
12-27 16:06:13.513 20962 20962 F DEBUG : x4 003d3d3d3d3d204a x5 0000008000000080 x6 26415e3d44495400 x7 0000000000008036
12-27 16:06:13.513 20962 20962 F DEBUG : x8 0072006500640069 x9 0000000000000001 x10 0000000000000003 x11 00000000000000ff
12-27 16:06:13.514 20962 20962 F DEBUG :
12-27 16:06:13.514 20962 20962 F DEBUG : backtrace:
12-27 16:06:13.514 20962 20962 F DEBUG : #00 pc 0000000000028228 /data/app/com.chenxf.opengles-Xbv907eJgfjlz8Zq9XfKYQ==/base.apk (offset 0x3675000)
3.2 Análisis de causas
No hay pila, por lo que también es a través del registro para ver dónde se ejecuta al final. Aquí hay una lista de códigos:
class TextSample
{
public:
TextSample();
virtual ~TextSample();
virtual void Init();
virtual void Draw(int screenW, int screenH);
private:
Shader *m_pShader;
};
TextSample::TextSample() {
}
void TextSample::Draw(int screenW, int screenH) {
if(m_pShader == nullptr)
return;
DEBUG_LOGCATE();
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0, 1.0, 1.0, 1.0);
// enable alpha blending
// ------------
DEBUG_LOGCATE();
m_pShader->use();
}
El registro se bloquea en m_pShader->use()
.
¡Pero lo extraño es que se ha juzgado que el frente de la función está vacío!if(m_pShader == nullptr) return;
¿por qué? Debido a que
m_pShader está definido, pero no inicializado, a diferencia de JAVA, para C++, siempre que se genere un objeto TextSample, ¡el puntero interno de m_pShader no está vacío!
3.3 Soluciones
La solución es muy simple, en el constructor, ¡asegúrese de que el puntero esté inicializado!
TextSample::TextSample() {
m_pShader = nullptr;
}
¡Esta es también la diferencia entre el trabajo de C++ y el trabajo de JAVA! JAVA no necesita preocuparse por los punteros. Se define una variable y no es necesario inicializarla. Está vacía de forma predeterminada.