python Google एनडीबी पुस्तकालय में मेमोरी रिसाव




google-app-engine memory-leaks (3)

मुझे लगता है कि ndb लाइब्रेरी में मेमोरी रिसाव है लेकिन मुझे नहीं पता है

क्या नीचे वर्णित समस्या से बचने का कोई तरीका है?
क्या आपको यह पता लगाने के लिए परीक्षण की एक अधिक सटीक अवधारणा है कि समस्या कहां है?

इसी तरह मैंने इस समस्या को पुन: उत्पन्न किया:

मैंने 2 फाइलों के साथ एक न्यूनतम गूगल ऐप इंजिन अनुप्रयोग बनाया
app.yaml :

application: myapplicationid
version: demo
runtime: python27
api_version: 1
threadsafe: yes


handlers:
- url: /.*
  script: main.APP

libraries:
- name: webapp2
  version: latest

main.py :

# -*- coding: utf-8 -*-
"""Memory leak demo."""
from google.appengine.ext import ndb
import webapp2


class DummyModel(ndb.Model):

    content = ndb.TextProperty()


class CreatePage(webapp2.RequestHandler):

    def get(self):
        value = str(102**100000)
        entities = (DummyModel(content=value) for _ in xrange(100))
        ndb.put_multi(entities)


class MainPage(webapp2.RequestHandler):

    def get(self):
        """Use of `query().iter()` was suggested here:
            https://code.google.com/p/googleappengine/issues/detail?id=9610
        Same result can be reproduced without decorator and a "classic"
            `query().fetch()`.
        """
        for _ in range(10):
            for entity in DummyModel.query().iter():
                pass # Do whatever you want
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, World!')


APP = webapp2.WSGIApplication([
    ('/', MainPage),
    ('/create', CreatePage),
])

मैंने आवेदन को अपलोड किया, जिसे एक बार कहा जाता है /create
उसके बाद, उदाहरण के द्वारा उपयोग की जाने वाली स्मृति को प्रत्येक कॉल / बढ़ जाती है जब तक यह त्रुटि के कारण बंद हो जाता है, Exceeded soft private memory limit of 128 MB with 143 MB after servicing 5 requests total हो जाती है।

स्मृति उपयोग ग्राफ का उदाहरण (आप स्मृति वृद्धि और क्रैश देख सकते हैं):

नोट: समस्या webapp2 तरह एक अन्य ढांचे के साथ फिर से प्रकाशित की जा सकती है, जैसे web.py


अधिक जांच के बाद, और एक Google इंजीनियर की मदद से, मुझे अपनी मेमोरी खपत में दो स्पष्टीकरण मिले हैं

संदर्भ और धागा

ndb.Context एक "धागा स्थानीय" ऑब्जेक्ट है और केवल जब धागा में कोई नया अनुरोध आ जाता है तो उसे केवल मंजूरी मिल जाती है। इसलिए धागा अनुरोधों के बीच में इसे पकड़ता है कई धागे एक GAE उदाहरण में मौजूद हो सकते हैं और यह एक सैकड़ों अनुरोध ले सकता है इससे पहले कि किसी थ्रेड को दूसरी बार उपयोग किया जाता है और इसका संदर्भ संरूपित होता है।
यह स्मृति रिसाव नहीं है, लेकिन स्मृति में आकार की संदर्भ में उपलब्ध स्मृति को छोटे GAE उदाहरण से अधिक हो सकता है।

युक्ति:
आप GAE इंस्टेंस में उपयोग किए गए थ्रेड्स की संख्या को कॉन्फ़िगर नहीं कर सकते इसलिए प्रत्येक संदर्भ को सबसे छोटा संभव रखने के लिए सबसे अच्छा होना चाहिए। इन-संदर्भ कैश से बचें, और प्रत्येक अनुरोध के बाद इसे साफ़ करें।

इवेंट की कतार

ऐसा लगता है कि एनडीबी इस बात की गारंटी नहीं देता है कि एक अनुरोध के बाद घटना कतार रिक्त हो गया है। फिर यह स्मृति रिसाव नहीं है। लेकिन यह आपके धागा संदर्भ में Futures छोड़ देता है, और आप पहली समस्या पर वापस आ गए हैं।

युक्ति:
एनडीबी का उपयोग करें @ndb.toplevel@ndb.toplevel साथ अपने सभी कोड को लपेटें


एनडीबी के साथ एक ज्ञात मुद्दा है आप इसके बारे में यहां पढ़ सकते हैं और यहाँ आसपास एक काम है :

Fetch_page के साथ मनाया गया गैर नियतिवाद, eventloop.rpcs के पुनरावृत्ति आदेश के कारण होता है, जो डेटास्टोर_आरपीसी मल्टीआरपीसीवाइट_एआई () और एपीप्रोक्सी_स्टाबु_मैप .__ चेक_ऑन को पास किया जाता है Iterator से अंतिम आरपीसी का चयन करता है

10 के पेज_ आकार के साथ लाए जाने पर आरएपीसी को गिनती = 10, सीमा = 11, एक मानक तकनीक के साथ बैकएंड को और अधिक सही ढंग से निर्धारित करने के लिए मजबूर किया गया है कि क्या अधिक परिणाम हैं या नहीं। यह 10 परिणाम देता है, लेकिन जिस तरह से क्वेरी इटरेटर को सुलझाने में एक बग की वजह से, एक आरपीसी को अंतिम प्रविष्टि (प्राप्त कर्सर और गणना = 1 का उपयोग करके) में जोड़ा जाता है एनडीबी तब इस आरपीसी को संसाधित किए बिना संस्थाओं का बैच देता है। मुझे विश्वास है कि इस आरपीसी का मूल्यांकन तब तक नहीं किया जाएगा जब तक कि यादृच्छिक पर चयनित नहीं हो (यदि मल्टीआरपीसी एक आवश्यक आरपीसी से पहले खपत करता है), क्योंकि यह क्लाइंट कोड ब्लॉक नहीं करता है।

वैकल्पिक हल: उपयोग करें ()। इस फ़ंक्शन में यह समस्या नहीं है (गणना और सीमा समान होगी) इसके बाद के संस्करण की वजह से फ़ेच पेज के साथ जुड़े प्रदर्शन और स्मृति मुद्दों के लिए एक वैकल्पिक हल के रूप में इस्तेमाल किया जा सकता है।


एक संभावित समाधान संदर्भ विधि पर प्राप्त करने के लिए context.clear_cache () और gc.collect () का उपयोग करें।

def get(self):

    for _ in range(10):
        for entity in DummyModel.query().iter():
            pass # Do whatever you want
    self.response.headers['Content-Type'] = 'text/plain'
    self.response.write('Hello, World!')
    context = ndb.get_context()
    context.clear_cache()
    gc.collect()






webapp2