2012-06-11 24 views
15

मैं कोड कोड के बारे में node-canvas पर टीजे को बगिंग कर रहा हूं, मैं एक नोड मॉड्यूल के एक फोर्क में काम कर रहा हूं जिसे उसने लिखा और रखरखाव किया है।nodejs देशी C++ npm मॉड्यूल मेमोरी त्रुटि, कैरो छवि प्रसंस्करण

मुझे हमारे पाइपलाइन संसाधनों को मारने के लिए Canvas.toBuffer() मिला और एक विकल्प बनाया जो आसानी से एक पीएनजी बफर/मीडिया यूआरएल के बिना कैनवास से छवि में परिवर्तित हो जाएगा। समस्या यह है कि कैरो एक रहस्यमय जानवर है, और नोड मॉड्यूल के भीतर आवंटित स्मृति के बारे में चिंता का एक अतिरिक्त स्तर है क्योंकि मां v8 द्वारा जीसीडी प्राप्त नहीं किया गया है। मैंने सभी आवश्यक कार्यों में उचित हैंडलस्कोप जोड़े हैं जो वी 8 डेटा तक पहुंचते हैं।

मैं अपने मैक सेटअप (6.18) पर हजारों बार Canvas.loadImage (छवि) विधि का परीक्षण करने में सक्षम था, साथ ही नोड के समान संस्करण को चलाने वाले हमारे उबंटू/उत्पादन सर्वर पर अकेले परीक्षणों का परीक्षण करने में सक्षम था। लेकिन जब कोड पृष्ठभूमि प्रक्रिया/सर्वर के रूप में चलाया जाता है और गियरमैन द्वारा समन्वित किया जाता है तो मुझे कुछ "रोचक" मेमोरी/सेगफाल्ट मिल रहा है।

इसके अलावा मुझे नोड-कैनवास में परिभाषित कक्षाओं के किसी भी तरीके को कॉल करने में समस्या हो रही है जो हेडर फ़ाइलों के भीतर इनलाइन नहीं हैं। एक साइड सवाल के रूप में सामान्य देशी स्रोत कोड संकुल बनाने का सबसे अच्छा तरीका क्या है जो अन्य नोड मॉड्यूल भरोसा कर सकते हैं?

मैंने समस्या को पुनर्जीवित करने और इसे जीडीबी, नोड_जी, और प्रतीकों और डीबग झंडे के साथ बनाए गए सभी नोड मॉड्यूल के साथ चलाने की कोशिश की है। लेकिन स्रोत के बाहर एक lib में त्रुटि फसल अप मैं एक स्टैक ट्रेस प्राप्त कर सकते हैं।

यहां संदर्भ के लिए जहां मैं लोड इमेजडेटा कहता हूं और जब यह विभिन्न उत्पादन स्थितियों में स्थानीय स्तर पर चलता है, तो हमारे उत्पादन माहौल में सावधानीपूर्वक एक फ्रेम सर्वर के भीतर टकराया जाता है, ऐसा लगता है कि कल segfaults का कारण बन रहा है (जिस दिन कल हमारे पास node_g gdb करने की कोशिश कर रहा था सर्वर कोड लेकिन फ्रेम सर्वर gearman ... टी एल द्वारा की शुरूआत कर रहे हैं, डॉ मूल कारण स्टैक ट्रेस नहीं मिला)

https://github.com/victusfate/node-canvas/blob/master/src/Canvas.cc#L497

Handle<Value> 
Canvas::LoadImage(const Arguments &args) { 
    HandleScope scope; 
    LogStream mout(LOG_DEBUG,"node-canvas.paint.ccode.Canvas.LoadImage");  
    mout << "Canvas::LoadImage top " << LogStream::endl; 

    Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This()); 
    if (args.Length() < 1) { 
    mout << "Canvas::LoadImage Error requires one argument of Image type " << LogStream::endl; 
    return ThrowException(Exception::TypeError(String::New("Canvas::LoadImage requires one argument of Image type"))); 
    } 

    Local<Object> obj = args[0]->ToObject(); 
    Image *img = ObjectWrap::Unwrap<Image>(obj); 
    canvas->loadImageData(img); 
    return Undefined(); 
} 

void Canvas::loadImageData(Image *img) { 
    LogStream mout(LOG_DEBUG,"node-canvas.paint.ccode.Canvas.loadImageData");  
    if (this->isPDF()) { 
    mout << "Canvas::loadImageData pdf canvas type " << LogStream::endl; 
    cairo_surface_finish(this->surface()); 
    closure_t *closure = (closure_t *) this->closure(); 

    int w = cairo_image_surface_get_width(this->surface()); 
    int h = cairo_image_surface_get_height(this->surface()); 

    img->loadFromDataBuffer(closure->data,w,h); 
    mout << "Canvas::loadImageData pdf type, finished loading image" << LogStream::endl; 
    } 
    else { 
    mout << "Canvas::loadImageData data canvas type " << LogStream::endl; 
    cairo_surface_flush(this->surface()); 
    int w = cairo_image_surface_get_width(this->surface()); 
    int h = cairo_image_surface_get_height(this->surface()); 

    img->loadFromDataBuffer(cairo_image_surface_get_data(this->surface()),w,h); 
    mout << "Canvas::loadImageData image type, finished loading image" << LogStream::endl; 
    } 
} 

और यहाँ इमेज वर्तमान पद्धति कैसा दिखता है (मैंने कुछ लॉगिंग जानकारी पर टिप्पणी की है) https://github.com/victusfate/node-canvas/blob/master/src/Image.cc#L240

/* 
* load from data buffer width*height*4 bytes 
*/ 
cairo_status_t 
Image::loadFromDataBuffer(uint8_t *buf, int width, int height) { 
    this->clearData(); 
    int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width); // 4*width + ? 
    this->_surface = cairo_image_surface_create_for_data(buf,CAIRO_FORMAT_ARGB32,width,height,stride); 
    this->data_mode = DATA_IMAGE; 
    this->loaded(); 
    cairo_status_t status = cairo_surface_status(_surface); 
    if (status) return status; 
    return CAIRO_STATUS_SUCCESS; 
} 

कोई भी मदद, समर्थक युक्तियाँ, सहायता, या प्रोत्साहन के शब्दों की सराहना की जाएगी।

मूलतः google groups

+3

हम उत्पादन में नोड-कैनवास का भी उपयोग कर रहे हैं और ~ 200 छवियों (मेमोरी लीक और विखंडन के कारण) को प्रस्तुत करने के बाद मारे गए और पुनरारंभ किए गए स्टैंडअलोन प्रक्रियाएं हैं। स्मृति ओवररन्स के लिए Valgrind के साथ अपने मूल एक्सटेंशन की जांच करें: http://valgrind.org/docs/manual/QuickStart.html इस टूल को पहले से ही एनवी परीक्षण में सेगमेंटेशन उल्लंघनों के कारण प्रकट करना चाहिए। –

+0

धन्यवाद teemu, हम छवियों के बैचों के बीच फाड़ और निर्माण ~ 24-> 100 या तो। –

+0

@TeemuIkonen मुझे पहले ओएसएक्स साइड और लिनक्स दोनों पर वाल्ग्रिंड का उपयोग करने में परेशानी थी, परिणाम की भावना बनाने के लिए कोई सुझाव (ओएस एक्स पर तुरंत जमे हुए, लिनक्स पक्ष पर एक त्रुटि का उल्लेख करने के लिए कुछ कॉल ले गए) –

उत्तर

1

समझ गया!

मैं आज एक और लाइब्रेरी पर काम कर रहा था जो डेटा बफर से बनाए गए कैरोम और खोजी गई सतहों का उपयोग करता है, उन बफरों को सतह पर तब तक रहने की आवश्यकता होती है जब तक सतह होती है।

http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-image-surface-create-for-data

"प्रदान की पिक्सेल डेटा के लिए एक छवि सतह बनाता है। उत्पादन बफर के आसपास जब तक cairo_surface_t नष्ट हो जाता है या cairo_surface_finish() सतह पर कहा जाता है रखा जाना चाहिए। डेटा की प्रारंभिक सामग्री का उपयोग किया जाएगा आरंभिक छवि सामग्री के रूप में, यदि आप इसे साफ़ करना चाहते हैं, तो उदाहरण के लिए, cairo_rectangle() और cairo_fill() का उपयोग करके आपको बफर को स्पष्ट रूप से साफ़ करना होगा। "

मैंने एक सतह पेश की जो एक अस्थायी बफर से बनाई गई थी। नोड कैनवास कांटा में


आसान समाधान:

वहाँ एक सदस्य चर कहा है _data जो मैं करने के लिए एक स्थानीय रूप से malloced डेटा बफर, जो रूप में लंबे समय काहिरा सतह करता है पर रहेंगे असाइन कर सकते हैं।


समाधान:

एक सामान्य तरीके से एक सतह में एक बफर कॉपी करने के लिए बफर से एक अस्थायी सतह बनाने के लिए है, तो एक आवंटित की सतह पर अस्थायी सतह से आकर्षित और जाने काहिरा प्रबंधन यह है अपनी याददाश्त

यह कैपि के कार्यान्वयन के लिए सी एपीआई के साथ ऐसा कुछ दिखाई देगा।

cairo_surface_t *pTmp = cairo_image_surface_create_for_data (
    data 
, CAIRO_FORMAT_ARGB32 
, width 
, height 
, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); 

_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32 
, width 
, height); 

cairo_t *cr = cairo_create (_surface); 
cairo_set_source_surface (cr, pTmp, x, y); 
cairo_paint (cr); 
1

से इसके अलावा मैं मुसीबत कक्षाएं नोड कैनवास में परिभाषित किया गया है कि हेडर फाइल के भीतर इनलाइन नहीं कर रहे हैं करने के तरीकों में से किसी को बुला रही है। साइड प्रश्न के रूप में सामान्य देशी स्रोत कोड पैकेज बनाने का सबसे अच्छा तरीका क्या है जो अन्य नोड मॉड्यूल भरोसा कर सकते हैं?

जबकि मेरे पास स्मृति समस्या/सीईजी गलती का कोई जवाब नहीं है, तो मैं अपने स्टेजिंग वातावरण में दौड़ रहा था। मेरे पास देशी नोड मॉड्यूल के साथ पुन: प्रयोज्य पुस्तकालयों का निर्माण करने का उत्तर है।

मैं सभी स्वतंत्र देशी नोड मॉड्यूल के लिए गिट सबमिड्यूल का उपयोग कर रहा हूं, और साझा ऑब्जेक्ट उत्पन्न करने के लिए या नहीं, यह निर्दिष्ट करने के लिए अपनी प्रत्येक wscript या binding.gyp फ़ाइलों के लिए एक सशर्त प्रीप्रोसेसर परिभाषा जोड़ा है।

अद्यतनवैकल्पिक रूप से अद्वितीय init समारोह के नाम या नामस्थान मॉड्यूल आरंभीकरण कॉल (इस स्थापना के लिए चले गए) के चारों ओर कर सकते हैं।

इसके अतिरिक्त मैं डिबगिंग या कोड अनुभागों को फिर से लिखने में सहायता के लिए इस नए पैकेज का उपयोग करूँगा (मैं कई दूरस्थ पुस्तकालयों के उपयोग को अधिक समय व्यतीत नहीं कर सकता)।

WScript या binding.gyp

flags = ['-D_NAME_NODE_MODULE', '-O3', '-Wall', '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE_SOURCE', '-msse2'] 
तो एक आरंभीकरण फ़ाइल

#ifdef _NAME_NODE_MODULE 

extern "C" { 
    static void init(Handle<Object> target) { 
    HandleScope scope; 
    NODE_SET_METHOD(target, "someFunction", someFunction); 
    } 

    NODE_MODULE(moduleName, init); 
} 

#endif 

इस तरह एक नोड देशी मॉड्यूल केवल जब ध्वज सेट है में जोड़ा जाता है में

में

। अन्यथा इसे सामान्य रूप से जोड़ा जा सकता है (जैसे किसी अन्य नोड मॉड्यूल में)।

संबंधित मुद्दे