2016-01-21 52 views
5

在進行重構時進入此操作。調用getProperties()會導致我們的CPU使用率激增。我們發現如果你有一個沒有關聯屬性的getter,當你調用getProperties()時,getter被調用超過1000次。修復/解決方法很明顯,我們知道它與元編程有關,但爲什麼會發生這種情況(groovy源代碼中的哪一點)?請參閱下面的常規腳本代碼:Groovy getProperties()調用1000次以上的不存在屬性調用getter

class tester { 

    int count = 0 

    public getVar() { 
     println count++ + " getVar() called!" 
     return var 
    } 
} 

def t = new tester() 

t.getProperties() 

println "done!" 

您應該看到調用超過1000次的getVar()。 1068對我們來說確切無誤。

+1

很奇怪。我只是在Groovy的Web控制檯http://groovyconsole.appspot.com/上試過這個,我看到它執行了110次。 –

+9

這是因爲這行'return var'。這實際上是在遞歸中調用'getVar()'本身,因爲'return var'與調用'return getVar()'相同。它會打印計數,直到堆棧溢出。 – dmahapatro

+2

'return var'是問題所在。 –

回答

0

這個問題可能已經在評論中得到了回答,但我更深入地挖掘了一下,以回答「groovy源代碼中的什麼點」部分。

當你的tester的實例調用getProperties()的Groovy會做它的魔力,最後調用DefaultGroovyMethods#getProperties(Object)這(在Groovy 2.4.7)看起來是這樣的:

public static Map getProperties(Object self) { 
    List<PropertyValue> metaProps = getMetaPropertyValues(self); // 1 
    Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size()); 

    for (PropertyValue mp : metaProps) { 
     try { 
      props.put(mp.getName(), mp.getValue()); // 2 
     } catch (Exception e) { 
      LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e); 
     } 
    } 
    return props; 
} 

首先,Groovy中確定的元屬性給定的對象(見1)。這將返回三個屬性:

  • var:吸氣劑只(getVar()),沒有setter,沒有實地
  • class:唯一吸氣劑(從Object繼承),沒有setter,沒有實地
  • count:吸氣, setter(均由Groovy生成)和字段

您可以通過致電t.getMetaPropertyValues()輕鬆驗證此內容。

接下來,Groovy嘗試獲取每個屬性的當前值並將其放入一個映射中(請參閱2)。當它達到var時,它記得var有一個吸氣劑(即getVar())並調用它。然而,getVar()又會返回var。對於Groovy來說,這與第一步中確定的屬性完全相同。再一次,它調用它的getter getVar()並且無限循環開始。

在某一點上,根據不同的JVM,這導致StackOverflowError,這正是這個網站是所有關於:-D

相關問題