V8内存泄漏和条件跳转

时间:2019-06-25 14:35:48

标签: c++ v8

我在我的C应用程序中嵌入了V8。我可以在C应用程序中执行javascript。但是,当我尝试运行C应用程序时,看到大量内存泄漏和条件跳转。我总共有4个文件。

1。 mjse_int.h

typedef struct
{
    std::unique_ptr<v8::Platform> platform;
    v8::Isolate::CreateParams create_params;
    v8::Isolate *isolate;
}MJSEInstance;

2。 mjse.h

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Create MJSE instance
*/
void *mjse_create_instance(char **argv);

/**
* @brief Destroy MJSE instance
* @param instance -> MJSE instance
*/
void mjse_destroy_instance(void *minstance);

/**
* @brief Executes a script
* @param minstance - MJSE instance
* @param script - the javascript
* @param scriptlen - Length of script
*/
void mjse_execute_script(void *minstance, char *script, int scriptlen);

#ifdef __cplusplus
}
#endif

#endif

3。 mjse.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
#include "mjse.h"
#include "mjse_int.h"

extern "C"  {

using namespace v8;

void *mjse_create_instance(char **argv)
{
    MJSEInstance *instance = (MJSEInstance *)calloc(1, sizeof(MJSEInstance));

    v8::V8::InitializeICUDefaultLocation(argv[0]);
    v8::V8::InitializeExternalStartupData(argv[0]);
    instance->platform = v8::platform::NewDefaultPlatform();

    v8::V8::InitializePlatform(instance->platform.get());
    v8::V8::Initialize();

    instance->create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
    instance->isolate = v8::Isolate::New(instance->create_params);

    printf("Version: %s\n", v8::V8::GetVersion());

    return instance;
}

void mjse_destroy_instance(void *minstance)
{
    MJSEInstance *instance = (MJSEInstance *)minstance;

    if(instance == NULL)
        return;

    if(instance->isolate)
    {
        instance->isolate->Dispose();
    }

    v8::V8::Dispose();
    v8::V8::ShutdownPlatform();

    if(instance->create_params.array_buffer_allocator)
    {
        delete instance->create_params.array_buffer_allocator;
    }

    free(instance);
}

void mjse_execute_script(void *minstance, char *script, int scriptlen)
{
    MJSEInstance *instance = (MJSEInstance *)minstance;

    v8::Isolate::Scope isolate_scope(instance->isolate);

    // Create a stack-allocated handle scope.
    v8::HandleScope handle_scope(instance->isolate);

    // Create a new context.
    v8::Local<v8::Context> context = v8::Context::New(instance->isolate);

    // Enter the context for compiling and running the hello world script.
    v8::Context::Scope context_scope(context);

    {
        // Create a string containing the JavaScript source code.
        v8::Local<v8::String> source =
          v8::String::NewFromUtf8(instance->isolate, script,
          v8::NewStringType::kNormal).ToLocalChecked();

        // Compile the source code.
        v8::Local<v8::Script> script =
          v8::Script::Compile(context, source).ToLocalChecked();

        // Run the script to get the result.
        v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

        // Convert the result to an UTF8 string and print it.
        v8::String::Utf8Value utf8(instance->isolate, result);
        printf("%s\n", *utf8);
    }
}
}

使用这3个文件,我建立了一个.so文件。现在我的测试代码如下所示。

4。 main.c

int main(int argc, char **argv)
{
    int len;
    char *script;
    void *instance;

    instance = mjse_create_instance(argv);

    script =    "function js_add_elements1(var1, var2) \
                { \
                    var var3 = parseInt(var1) + parseInt(var2); \
                    var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; \
                    return result; \
                };\
                js_add_elements1(2, 3);";

    len = strlen(script);
    mjse_execute_script(instance, script, len);

    script =    "function js_add_elements2(var1, var2) \
                { \
                    var var3 = parseInt(var1) + parseInt(var2); \
                    var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; \
                    return result; \
                };\
                js_add_elements2(2, 3);";

    len = strlen(script);
    mjse_execute_script(instance, script, len);

    script =    "function js_add_elements3(var1, var2) \
                { \
                    var var3 = parseInt(var1) + parseInt(var2); \
                    var result = 'Addition of ' + var1 + ' and ' + var2 + ' results ' + var3; \
                    return result; \
                };\
                js_add_elements3(2, 3);";

    len = strlen(script);
    mjse_execute_script(instance, script, len);

    mjse_destroy_instance(instance);

    return 0;
}

以此,我构建了main.c并进行了测试。输出如下。

  

版本:7.7.0(候选)
2和3结果的加法5
  2和3的结果5的加法
2和3的结果5的加法

从功能角度看,它看起来不错。但是,有很多条件跳转和内存泄漏,如下所示(只有很少的条件跳转才能减小大小)。

==31273== Conditional jump or move depends on uninitialised value(s)
==31273==    at 0x5DB55E8: v8::internal::DeclarationScope::CheckConflictingVarDeclarations() (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x599DCE8: v8::internal::PreParser::PreParseFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, v8::internal::ProducedPreparseData**, int) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x597C6B5: v8::internal::Parser::SkipFunction(v8::internal::AstRawString const*, v8::internal::FunctionKind, v8::internal::FunctionLiteral::FunctionType, v8::internal::DeclarationScope*, int*, int*, v8::internal::ProducedPreparseData**) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x5970495: v8::internal::Parser::ParseFunctionLiteral(v8::internal::AstRawString const*, v8::internal::Scanner::Location, v8::internal::FunctionNameValidity, v8::internal::FunctionKind, int, v8::internal::FunctionLiteral::FunctionType, v8::internal::LanguageMode, v8::internal::ZoneList<v8::internal::AstRawString const*>*) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x5996C7A: v8::internal::ParserBase<v8::internal::Parser>::ParseHoistableDeclaration(int, v8::base::Flags<v8::internal::ParseFunctionFlag, int>, v8::internal::ZoneList<v8::internal::AstRawString const*>*, bool) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x596EFE6: v8::internal::Parser::DoParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x596E6D8: v8::internal::Parser::ParseProgram(v8::internal::Isolate*, v8::internal::ParseInfo*) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x599A4D9: v8::internal::parsing::ParseProgram(v8::internal::ParseInfo*, v8::internal::Isolate*) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x56EF5B5: v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo*, v8::internal::Isolate*, v8::internal::IsCompiledScope*) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x56F0EA8: v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, v8::internal::Compiler::ScriptDetails const&, v8::ScriptOriginOptions, v8::Extension*, v8::internal::ScriptData*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason, v8::internal::NativesFlag) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x56B5C64: v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate*, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /usr/local/mysys/system/libs/libmjse.so)
==31273==    by 0x56B6356: v8::ScriptCompiler::Compile(v8::Local<v8::Context>, v8::ScriptCompiler::Source*, v8::ScriptCompiler::CompileOptions, v8::ScriptCompiler::NoCacheReason) (in /usr/local/mysys/system/libs/libmjse.so)
==31273== 

==31273==    LEAK SUMMARY:<br>
==31273==    definitely lost: 144 bytes in 1 blocks<br>
==31273==    indirectly lost: 1,744 bytes in 11 blocks<br>
==31273==    possibly lost: 960 bytes in 3 blocks<br>
==31273==    still reachable: 1,474 bytes in 18 blocks<br>
==31273==    suppressed: 0 bytes in 0 blocks<br>

不确定这是怎么回事。在这方面的任何帮助,深表感谢。

编辑

按照RadosławCybulski的建议修改代码后,内存泄漏消失了。仅存在仍可访问的内存168字节。

但是仍然存在未初始化值的条件跳转(使用valgrind run)。我观察到的一件事是,如果删除javascript中的函数参数,则未显示这些针对未初始化值的条件跳转。说我将有如下所示的javascript。

char *jscript =  "function js_add_elements1() \
    { \
        return 10; \
    };\

js_add_elements1();";

使用上述javascript,我看不到未初始化值的条件内存跳转。可能是什么原因?

1 个答案:

答案 0 :(得分:1)

free(instance);

释放内存,但防止unique_ptr(平台成员)破坏。试试:

instance->~MJSEInstance();
free(instance):

或者甚至更好地使用new和delete代替malloc和free。