2011-12-16 6 views
14

मैंने एक वेबपृष्ठ बनाया है जो वेबस्केट पर बेस 64 एन्कोडेड बिटमैप्स प्राप्त करता है और फिर उन्हें कैनवास में खींचता है। यह पूरी तरह से काम करता है। सिवाय इसके कि, ब्राउज़र (चाहे फ़ायरफ़ॉक्स, क्रोम, या सफारी) प्रत्येक छवि के साथ स्मृति उपयोग बढ़ता है और कभी नीचे नहीं जाता है। तो, मेरे कोड या कुछ अन्य बग में एक स्मृति रिसाव होना चाहिए। अगर मैं context.drawImage पर कॉल को टिप्पणी करता हूं, तो स्मृति रिसाव नहीं होती है (लेकिन फिर निश्चित रूप से छवि कभी नहीं खींची जाती है)। नीचे मेरे वेबपृष्ठ से स्निपेट हैं। किसी भी मदद की सराहना की है। धन्यवाद!सफारी में डेटा यूआरआई रिसाव (था: एचटीएमएल 5 कैनवास के साथ मेमोरी लीक)

// global variables 
var canvas; 
var context; 

... 

ws.onmessage = function(evt) 
{ 
    var received_msg = evt.data; 
    var display_image = new Image(); 
    display_image.onload = function() 
    { 
     context.drawImage(this, 0, 0); 
    } 
    display_image.src = 'data:image/bmp;base64,'+received_msg; 
} 

... 

canvas=document.getElementById('ImageCanvas'); 
context=canvas.getContext('2d'); 

... 

<canvas id="ImageCanvas" width="430" height="330"></canvas> 

अद्यतन 12/19/2011

मैं इस समस्या को हल गतिशील बनाने/कैनवास प्रत्येक 100 चित्रों या तो नष्ट createElement/appendChild और removeChild साथ काम कर सकते हैं। उसके बाद, मेरे पास फ़ायरफ़ॉक्स और क्रोम के साथ कोई और मेमोरी समस्या नहीं है।

हालांकि, सफारी में अभी भी स्मृति उपयोग की समस्या है, लेकिन मुझे लगता है कि यह एक अलग समस्या है, जो कैनवास से संबंधित नहीं है। सफारी में छवि के "src" को बार-बार बदलने के साथ एक समस्या प्रतीत होती है, जैसे कि यह कभी भी इस स्मृति को मुक्त नहीं करेगा।

display_image.src = 'data:image/bmp;base64,'+received_msg; 

यह एक ही समस्या निम्नलिखित साइट पर वर्णित है: http://waldheinz.de/2010/06/webkit-leaks-data-uris/


अद्यतन 12/21/2011

मैं अपने प्राप्त base64 परिवर्तित करके इस सफारी समस्या को हल पाने के लिए उम्मीद कर रही थी एक ब्लॉब के लिए स्ट्रिंग (एक "dataURItoBlob" फ़ंक्शन जो मुझे इस साइट पर मिला) और window.URL.createObjectURL के साथ एक यूआरएल पर वापस, इस यूआरएल में मेरी छवि स्रोत सेट करना, और उसके बाद window.URL को कॉल करके मेमोरी को फ्री करना। revokeObjectURL। मुझे यह सब काम मिल गया, और क्रोम और फ़ायरफ़ॉक्स छवियों को सही तरीके से प्रदर्शित करता है। दुर्भाग्यवश, सफारी को ब्लॉबबिल्डर के लिए समर्थन नहीं दिख रहा है, इसलिए यह एक समाधान नहीं है जिसका मैं उपयोग कर सकता हूं। यह अजीब बात है, क्योंकि O'Reilly "प्रोग्रामिंग एचटीएमएल 5 एप्लीकेशन" पुस्तक सहित कई स्थानों में कहा गया है कि ब्लॉबबिल्डर सफारी/वेबकिट नाइटली बिल्ड्स में समर्थित है। मैंने http://nightly.webkit.org/ से नवीनतम विंडोज़ रात का निर्माण डाउनलोड किया और WebKit.exe चलाया लेकिन ब्लॉबबिल्डर और वेबकिटब्लोबबिल्डर अभी भी अनिर्धारित हैं।


अद्यतन 01/03/2012

ठीक है, मैं अंत में इस atob साथ बेस 64 एन्कोडेड डेटा URI स्ट्रिंग() डिकोडिंग और फिर एक पिक्सेल डेटा सरणी बनाने और कैनवास के लिए इसे लिखने के साथ द्वारा तय putImageData (देखें http://beej.us/blog/2010/02/html5s-canvas-part-ii-pixel-manipulation/)। इसे इस तरह से करना (एक छवि के "src" को लगातार संशोधित करने और ऑनलोड फ़ंक्शन में drawImage को कॉल करने के विरोध में), अब मुझे सफारी या किसी भी ब्राउज़र में मेमोरी लीक दिखाई नहीं दे रही है।

+0

क्या हुआ अगर आप छवि निकालने से पहले एक clearRect कॉल जोड़ने के लिए, या यदि आप अपने आप को स्थापित करने की चौड़ाई रीसेट चाल का उपयोग होता है? (http://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing) – Mikeb

+0

मैंने context.clearRect (0, 0, canvas.width, canvas.height) की कोशिश की है; drawImage से पहले लेकिन स्मृति रिसाव अभी भी होता है। – bglaudel

+0

क्या आप वाकई छवि पर संग्रहीत नहीं कर रहे हैं बस अगर आप पृष्ठ पर वापस जाते हैं तो यह इसे स्मृति से लोड कर सकता है? एक रनटाइम अनुकूलन हो सकता है। –

उत्तर

0

आप संभवतः छवि की तुलना में अधिक बार चित्र खींच रहे हैं। एक काउंटर जोड़ने का प्रयास करें और पृष्ठ को एक चेतावनी या पृष्ठ में एक div को आउटपुट करने के लिए यह देखने के लिए कि छवि कितनी बार खींची जा रही है।

3

वास्तविक कार्य कोड के बिना हम केवल अनुमान लगा सकते हैं कि क्यों।

यदि आप एक ही छवि भेज रहे हैं और आप हर बार एक नई छवि बना रहे हैं। ये गलत है।आप इस तरह कुछ करना चाहता हूँ चाहते हैं:

var images = {}; // a map of all the images 

ws.onmessage = function(evt) 
{ 
    var received_msg = evt.data; 
    var display_image; 
    var src = 'data:image/bmp;base64,'+received_msg; 
    // We've got two distinct scenarios here for images coming over the line: 
    if (images[src] !== undefined) { 
     // Image has come over before and therefore already been created, 
     // so don't make a new one! 
     display_image = images[src]; 
     display_image.onload = function() { 
      context.drawImage(this, 0, 0); 
     } 
    } else { 
     // Never before seen image, make a new Image() 
     display_image = new Image(); 
     display_image.onload = function() { 
      context.drawImage(this, 0, 0); 
     } 
     display_image.src = src; 
     images[src] = display_image; // save it for reuse 
    } 
} 

वहाँ और अधिक कुशल तरीके (मैं उदाहरण के लिए ऑनलोड कोड डुप्लिकेट कर रहा हूँ, और मैं अगर एक छवि पहले से ही पूरा हो गया है देखने के लिए जाँच नहीं कर रहा हूँ) है कि लिखने के लिए कर रहे हैं। हालांकि, मैं आपको उन हिस्सों को छोड़ दूंगा, आपको विचार मिल जाएगा।

+0

प्रत्येक छवि अद्वितीय है। – bglaudel

+0

यदि प्रत्येक छवि अद्वितीय है, और स्मृति उपयोग बढ़ता है क्योंकि आप प्रत्येक नई HTMLImageElement ('नई छवि()') बनाते हैं, यह सामान्य है! –

+0

फिर अगर मैं आकर्षित करने के लिए कॉल पर टिप्पणी करता हूं तो मेमोरी उपयोग स्तर क्यों रहता है? – bglaudel

0

यह बहुत दिलचस्प है। यह विभिन्न ब्राउज़र विक्रेताओं को एक बग के रूप में रिपोर्ट करने लायक है (मेरी भावना यह है कि यह नहीं होना चाहिए)। आप "ऐसा न करें, इसके बजाय ऐसा करें और ऐसा करें" के आधार पर प्रतिक्रिया दे सकते हैं लेकिन कम से कम आपको सही उत्तर पता चल जाएगा और ब्लॉग पोस्ट के लिए लिखने के लिए एक दिलचस्प बात है (अधिक लोग निश्चित रूप से भाग लेंगे इस मुद्दे)।

कोशिश करने की एक चीज़ छवि खींचने के लिए कॉल के बाद छवि स्रोत (और ऑनलोड हैंडलर) को परेशान कर रही है। यह सभी मेमोरी को मुक्त नहीं कर सकता है लेकिन इसे अधिकतर वापस मिल सकता है।

यदि यह काम नहीं करता है, तो आप हमेशा छवि वस्तुओं का एक पूल बना सकते हैं और कैनवास के लिए तैयार होने के बाद उनका पुनः उपयोग कर सकते हैं। यह एक परेशानी है क्योंकि आपको उन वस्तुओं की स्थिति को ट्रैक करना होगा और अपने पूल को उचित आकार में सेट करना होगा (या इसे यातायात के आधार पर बढ़ाना/हटाना)।

कृपया अपने परिणामों की रिपोर्ट करें। मुझे बहुत दिलचस्पी है क्योंकि मैं noVNC में कसपैन एन्कोडिंग में से एक के लिए एक समान तकनीक का उपयोग करता हूं (और मुझे यकीन है कि अन्य भी रुचि रखते हैं)।

1

मुझे विश्वास नहीं है कि यह एक बग है। समस्या यह प्रतीत होती है कि छवियों को एक दूसरे के शीर्ष पर रखा गया है। तो स्मृति को साफ़ करने के लिए, आपको इसमें नई छवि खींचने से पहले अपने कैनवास को साफ़ करने के लिए clearRect() का उपयोग करना होगा।

ctx.clearRect (0, 0, canvas.width, canvas.height);

How to clear your canvas matters

+0

मैंने देखा कि किसी कारण से कैनवास की ऊंचाई मेरे मामले में गलत लगती है। कोड नमूना में "कैनवास.हेइट" के रूप में छवि ऊंचाई का उपयोग करना चाल चल रहा है। – Stitch10925